1 // this file is a modified version for deadbeef player
2 /***************************************************************************
3  *             __________               __   ___.
4  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
5  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
6  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
7  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
8  *                     \/            \/     \/    \/            \/
9  *
10  * $Id$
11  *
12  * Copyright (C) 2007 Dave Chapman
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20  * KIND, either express or implied.
21  *
22  ****************************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 #include "../../config.h"
26 #endif
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <inttypes.h>
32 #include <unistd.h>
33 #include "../../deadbeef.h"
34 
35 #include <libasf/asf.h>
36 
37 #define MIN(x,y) ((x)<(y)?(x):(y))
38 #define MAX(x,y) ((x)>(y)?(x):(y))
39 
40 //#define trace(...) { fprintf (stderr, __VA_ARGS__); }
41 #define trace(fmt,...)
42 #define DEBUGF trace
43 
44 #define SKIP_BYTES(fd,x) {\
45     if (x > 0) {\
46         char buf[x];\
47         deadbeef->fread (buf, x, 1, fd);\
48     }\
49 }
50 
51 extern DB_functions_t *deadbeef;
52 
53 enum {
54     AFMT_WMAPRO = 1,
55     AFMT_WMAVOICE = 2,
56 };
57 
swap16(uint16_t value)58 static inline uint16_t swap16(uint16_t value)
59     /*
60        result[15..8] = value[ 7..0];
61        result[ 7..0] = value[15..8];
62        */
63 {
64     return (value >> 8) | (value << 8);
65 }
66 
67 
swap32(uint32_t value)68 static inline uint32_t swap32(uint32_t value)
69     /*
70       result[31..24] = value[ 7.. 0];
71       result[23..16] = value[15.. 8];
72       result[15.. 8] = value[23..16];
73       result[ 7.. 0] = value[31..24];
74     */
75 {
76     uint32_t hi = swap16(value >> 16);
77     uint32_t lo = swap16(value & 0xffff);
78     return (lo << 16) | hi;
79 }
80 
81 #if WORDS_BIGENDIAN
82 #define read_uint16be(fd,buf) deadbeef->fread((buf), 2, 1, (fd))
83 #define read_uint32be(fd,buf) deadbeef->fread((buf), 4, 1, (fd))
84 #define read_uint64be(fd,buf) deadbeef->fread((buf), 8, 1, (fd))
85 int read_uint16le(DB_FILE *fd, uint16_t* buf);
86 int read_uint32le(DB_FILE *fd, uint32_t* buf);
87 int read_uint64le(DB_FILE *fd, uint64_t* buf);
88 #define letoh16(x) swap16(x)
89 #define letoh32(x) swap32(x)
90 #define htole16(x) swap16(x)
91 #define htole32(x) swap32(x)
92 #define betoh16(x) (x)
93 #define betoh32(x) (x)
94 #define htobe16(x) (x)
95 #define htobe32(x) (x)
96 #define swap_odd_even_be32(x) swap_odd_even32(x)
97 #define swap_odd_even_le32(x) (x)
98 #else
99 #define letoh16(x) (x)
100 #define letoh32(x) (x)
101 #define htole16(x) (x)
102 #define htole32(x) (x)
103 #define betoh16(x) swap16(x)
104 #define betoh32(x) swap32(x)
105 //#define htobe16(x) swap16(x)
106 //#define htobe32(x) swap32(x)
107 #define swap_odd_even_be32(x) (x)
108 #define swap_odd_even_le32(x) swap_odd_even32(x)
109 int read_uint16be(DB_FILE *fd, uint16_t* buf);
110 int read_uint32be(DB_FILE *fd, uint32_t* buf);
111 int read_uint64be(DB_FILE *fd, uint64_t* buf);
112 #define read_uint16le(fd,buf) deadbeef->fread((buf), 2, 1, (fd))
113 #define read_uint32le(fd,buf) deadbeef->fread((buf), 4, 1, (fd))
114 #define read_uint64le(fd,buf) deadbeef->fread((buf), 8, 1, (fd))
115 #endif
116 
117 
118 #if !WORDS_BIGENDIAN
119 /* Read an unsigned 16-bit integer from a big-endian file. */
read_uint16be(DB_FILE * fd,uint16_t * buf)120 int read_uint16be(DB_FILE *fd, uint16_t* buf)
121 {
122   size_t n;
123 
124   n = deadbeef->fread(buf, 1, 2, fd);
125   *buf = betoh16(*buf);
126   return n;
127 }
128 /* Read an unsigned 32-bit integer from a big-endian file. */
read_uint32be(DB_FILE * fd,uint32_t * buf)129 int read_uint32be(DB_FILE *fd, uint32_t* buf)
130 {
131   size_t n;
132 
133   n = deadbeef->fread(buf, 1, 4, fd);
134   *buf = betoh32(*buf);
135   return n;
136 }
137 /* Read an unsigned 64-bit integer from a big-endian file. */
read_uint64be(DB_FILE * fd,uint64_t * buf)138 int read_uint64be(DB_FILE *fd, uint64_t* buf)
139 {
140   size_t n;
141   uint8_t data[8];
142   int i;
143 
144   n = deadbeef->fread(data, 1, 8, fd);
145 
146   for (i=0, *buf=0; i<=7; i++) {
147        *buf <<= 8;
148        *buf |= data[i];
149   }
150   return n;
151 }
152 #else
153 /* Read unsigned integers from a little-endian file. */
read_uint16le(DB_FILE * fd,uint16_t * buf)154 int read_uint16le(DB_FILE *fd, uint16_t* buf)
155 {
156   size_t n;
157 
158   n = deadbeef->fread((char*) buf, 1, 2, fd);
159   *buf = letoh16(*buf);
160   return n;
161 }
read_uint32le(DB_FILE * fd,uint32_t * buf)162 int read_uint32le(DB_FILE *fd, uint32_t* buf)
163 {
164   size_t n;
165 
166   n = deadbeef->fread(buf, 1, 4, fd);
167   *buf = letoh32(*buf);
168   return n;
169 }
read_uint64le(DB_FILE * fd,uint64_t * buf)170 int read_uint64le(DB_FILE *fd, uint64_t* buf)
171 {
172   size_t n;
173   uint8_t data[8];
174   int i;
175 
176   n = deadbeef->fread(data, 1, 8, fd);
177 
178   for (i=7, *buf=0; i>=0; i--) {
179        *buf <<= 8;
180        *buf |= data[i];
181   }
182 
183   return n;
184 }
185 #endif
186 
187 /* TODO: Just read the GUIDs into a 16-byte array, and use memcmp to compare */
188 struct guid_s {
189     uint32_t v1;
190     uint16_t v2;
191     uint16_t v3;
192     uint8_t  v4[8];
193 };
194 typedef struct guid_s guid_t;
195 
196 struct asf_object_s {
197     guid_t       guid;
198     uint64_t     size;
199     uint64_t     datalen;
200 };
201 typedef struct asf_object_s asf_object_t;
202 
203 static const guid_t asf_guid_null =
204 {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
205 
206 /* top level object guids */
207 
208 static const guid_t asf_guid_header =
209 {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
210 
211 static const guid_t asf_guid_data =
212 {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
213 
214 static const guid_t asf_guid_index =
215 {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
216 
217 /* header level object guids */
218 
219 static const guid_t asf_guid_file_properties =
220 {0x8cabdca1, 0xa947, 0x11cf, {0x8E, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
221 
222 static const guid_t asf_guid_stream_properties =
223 {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
224 
225 static const guid_t asf_guid_content_description =
226 {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
227 
228 static const guid_t asf_guid_extended_content_description =
229 {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
230 
231 static const guid_t asf_guid_content_encryption =
232 {0x2211b3fb, 0xbd23, 0x11d2, {0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}};
233 
234 static const guid_t asf_guid_extended_content_encryption =
235 {0x298ae614, 0x2622, 0x4c17, {0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}};
236 
237 /* stream type guids */
238 
239 static const guid_t asf_guid_stream_type_audio =
240 {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
241 
asf_guid_match(const guid_t * guid1,const guid_t * guid2)242 static int asf_guid_match(const guid_t *guid1, const guid_t *guid2)
243 {
244     if((guid1->v1 != guid2->v1) ||
245        (guid1->v2 != guid2->v2) ||
246        (guid1->v3 != guid2->v3) ||
247        (memcmp(guid1->v4, guid2->v4, 8))) {
248         return 0;
249     }
250 
251     return 1;
252 }
253 
254 /* Read the 16 byte GUID from a file */
asf_readGUID(DB_FILE * fd,guid_t * guid)255 static void asf_readGUID(DB_FILE *fd, guid_t* guid)
256 {
257     read_uint32le(fd, &guid->v1);
258     read_uint16le(fd, &guid->v2);
259     read_uint16le(fd, &guid->v3);
260     deadbeef->fread(guid->v4, 8, 1, fd);
261 }
262 
asf_read_object_header(asf_object_t * obj,DB_FILE * fd)263 static void asf_read_object_header(asf_object_t *obj, DB_FILE *fd)
264 {
265     asf_readGUID(fd, &obj->guid);
266     read_uint64le(fd, &obj->size);
267     obj->datalen = 0;
268 }
269 
270 /* Parse an integer from the extended content object - we always
271    convert to an int, regardless of native format.
272 */
asf_intdecode(DB_FILE * fd,int type,int length)273 static int asf_intdecode(DB_FILE *fd, int type, int length)
274 {
275     uint16_t tmp16;
276     uint32_t tmp32;
277     uint64_t tmp64;
278 
279     if (type == 3) {
280         read_uint32le(fd, &tmp32);
281         SKIP_BYTES(fd,length - 4);
282         return (int)tmp32;
283     } else if (type == 4) {
284         read_uint64le(fd, &tmp64);
285         SKIP_BYTES(fd,length - 8);
286         return (int)tmp64;
287     } else if (type == 5) {
288         read_uint16le(fd, &tmp16);
289         SKIP_BYTES(fd,length - 2);
290         return (int)tmp16;
291     }
292 
293     return 0;
294 }
295 
296 /* Decode a LE utf16 string from a disk buffer into a fixed-sized
297    utf8 buffer.
298 */
299 #define MASK   0xC0 /* 11000000 */
300 #define COMP   0x80 /* 10x      */
301 
302 static const unsigned char utf8comp[6] =
303 {
304     0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
305 };
306 
307 /* Encode a UCS value as UTF-8 and return a pointer after this UTF-8 char. */
utf8encode(unsigned long ucs,unsigned char * utf8)308 unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8)
309 {
310     int tail = 0;
311 
312     if (ucs > 0x7F)
313         while (ucs >> (5*tail + 6))
314             tail++;
315 
316     *utf8++ = (ucs >> (6*tail)) | utf8comp[tail];
317     while (tail--)
318         *utf8++ = ((ucs >> (6*tail)) & (MASK ^ 0xFF)) | COMP;
319 
320     return utf8;
321 }
322 
323 
asf_utf16LEdecode(DB_FILE * fd,uint16_t utf16bytes,unsigned char ** utf8,int * utf8bytes)324 static void asf_utf16LEdecode(DB_FILE *fd,
325                               uint16_t utf16bytes,
326                               unsigned char **utf8,
327                               int* utf8bytes
328                              )
329 {
330     unsigned long ucs;
331     int n;
332     unsigned char utf16buf[256];
333     unsigned char* utf16 = utf16buf;
334     unsigned char* newutf8;
335 
336     n = deadbeef->fread(utf16buf, 1, MIN(sizeof(utf16buf), utf16bytes), fd);
337     utf16bytes -= n;
338 
339     while (n > 0) {
340         /* Check for a surrogate pair */
341         if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) {
342             if (n < 4) {
343                 /* Run out of utf16 bytes, read some more */
344                 utf16buf[0] = utf16[0];
345                 utf16buf[1] = utf16[1];
346 
347                 n = deadbeef->fread(utf16buf + 2, 1, MIN(sizeof(utf16buf)-2, utf16bytes), fd);
348                 utf16 = utf16buf;
349                 utf16bytes -= n;
350                 n += 2;
351             }
352 
353             if (n < 4) {
354                 /* Truncated utf16 string, abort */
355                 break;
356             }
357             ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18)
358                              | utf16[2] | ((utf16[3] - 0xDC) << 8));
359             utf16 += 4;
360             n -= 4;
361         } else {
362             ucs = (utf16[0] | (utf16[1] << 8));
363             utf16 += 2;
364             n -= 2;
365         }
366 
367         if (*utf8bytes > 6) {
368             newutf8 = utf8encode(ucs, *utf8);
369             *utf8bytes -= (newutf8 - *utf8);
370             *utf8 += (newutf8 - *utf8);
371         }
372 
373         /* We have run out of utf16 bytes, read more if available */
374         if ((n == 0) && (utf16bytes > 0)) {
375             n = deadbeef->fread(utf16buf, 1, MIN(sizeof(utf16buf), utf16bytes), fd);
376             utf16 = utf16buf;
377             utf16bytes -= n;
378         }
379     }
380 
381     *utf8[0] = 0;
382     --*utf8bytes;
383 
384     if (utf16bytes > 0) {
385         /* Skip any remaining bytes */
386         SKIP_BYTES(fd, utf16bytes);
387     }
388     return;
389 }
390 
391 static int
asf_add_disc_meta(DB_playItem_t * it,const char * disc)392 asf_add_disc_meta (DB_playItem_t *it, const char *disc) {
393     char *slash = strchr (disc, '/');
394     if (slash) {
395         // split into track/number
396         *slash = 0;
397         slash++;
398         deadbeef->pl_add_meta (it, "numdiscs", slash);
399     }
400     deadbeef->pl_add_meta (it, "disc", disc);
401     return 0;
402 }
403 
asf_parse_header(DB_FILE * fd,asf_waveformatex_t * wfx,DB_playItem_t * it)404 static int asf_parse_header(DB_FILE *fd, asf_waveformatex_t* wfx, DB_playItem_t *it)
405 {
406     asf_object_t current;
407     asf_object_t header;
408     uint64_t datalen = 0;
409     int i = 0;
410     int fileprop = 0;
411     uint64_t play_duration = 0;
412     uint16_t flags = 0;
413     uint32_t subobjects = 0;
414     uint8_t utf8buf[512];
415     int codectype = 0;
416     unsigned char id3buffer[2048];
417     unsigned char *id3buf = id3buffer;
418     int id3buf_remaining = sizeof(id3buffer);
419 
420     memset (&current, 0, sizeof (current));
421     memset (&header, 0, sizeof (header));
422     memset (&utf8buf, 0, sizeof (utf8buf));
423     memset (&id3buffer, 0, sizeof (id3buffer));
424 
425     asf_read_object_header((asf_object_t *) &header, fd);
426 
427     DEBUGF("header.size=%d\n",(int)header.size);
428     if (header.size < 30) {
429         /* invalid size for header object */
430         return ASF_ERROR_OBJECT_SIZE;
431     }
432 
433     read_uint32le(fd, &subobjects);
434 
435     /* Two reserved bytes - do we need to read them? */
436     SKIP_BYTES(fd, 2);
437 
438     DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);
439 
440     if (subobjects > 0) {
441         header.datalen = header.size - 30;
442 
443         /* TODO: Check that we have datalen bytes left in the file */
444         datalen = header.datalen;
445         DEBUGF("datalen: %d\n", datalen);
446 
447         for (i=0; i<(int)subobjects; i++) {
448             DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
449             if (datalen < 24) {
450                 DEBUGF("not enough data for reading object\n");
451                 break;
452             }
453 
454             asf_read_object_header(&current, fd);
455 
456             if (current.size > datalen || current.size < 24) {
457                 DEBUGF("invalid object size - current.size=%lld, datalen=%lld\n",current.size,datalen);
458                 break;
459             }
460 
461             if (asf_guid_match(&current.guid, &asf_guid_file_properties)) {
462                     if (current.size < 104)
463                         return ASF_ERROR_OBJECT_SIZE;
464 
465                     if (fileprop) {
466                         /* multiple file properties objects not allowed */
467                         return ASF_ERROR_INVALID_OBJECT;
468                     }
469 
470                     fileprop = 1;
471 
472                     /* Get the number of logical packets - uint64_t at offset 32
473                      * (Big endian byte order) */
474                     SKIP_BYTES(fd, 32);
475                     read_uint64le(fd, &wfx->numpackets);
476                     read_uint64le(fd, &wfx->play_duration);
477                     read_uint64le(fd, &wfx->send_duration);
478                     read_uint64le(fd, &wfx->preroll);
479                     read_uint32le(fd, &wfx->flags);
480 
481 //                    DEBUGF("****** length = %lld\n", wfx->play_duration);
482 
483                     /* Read the packet size - uint32_t at offset 68 */
484 //                    SKIP_BYTES(fd, 20);
485                     read_uint32le(fd, &wfx->packet_size);
486                     read_uint32le(fd, &wfx->max_packet_size);
487 
488                     /* Skip bytes remaining in object */
489                     SKIP_BYTES(fd, current.size - 24 - 72 - 4);
490             } else if (asf_guid_match(&current.guid, &asf_guid_stream_properties)) {
491                     guid_t guid;
492                     uint32_t propdatalen;
493 
494                     if (current.size < 78)
495                         return ASF_ERROR_OBJECT_SIZE;
496 
497 #if 0
498                     asf_byteio_getGUID(&guid, current->data);
499                     datalen = asf_byteio_getDWLE(current->data + 40);
500                     flags = asf_byteio_getWLE(current->data + 48);
501 #endif
502 
503                     asf_readGUID(fd, &guid);
504 
505                     SKIP_BYTES(fd, 24);
506                     read_uint32le(fd, &propdatalen);
507                     SKIP_BYTES(fd, 4);
508                     read_uint16le(fd, &flags);
509 
510                     if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
511                         DEBUGF("Found stream properties for non audio stream, skipping\n");
512                         SKIP_BYTES(fd,current.size - 24 - 50);
513                     } else if (wfx->audiostream == -1) {
514                         SKIP_BYTES(fd, 4);
515                         DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);
516 
517                         if (propdatalen < 18) {
518                             return ASF_ERROR_INVALID_LENGTH;
519                         }
520 
521 #if 0
522                         if (asf_byteio_getWLE(data + 16) > datalen - 16) {
523                             return ASF_ERROR_INVALID_LENGTH;
524                         }
525 #endif
526                         read_uint16le(fd, &wfx->codec_id);
527                         read_uint16le(fd, &wfx->channels);
528                         read_uint32le(fd, &wfx->rate);
529                         read_uint32le(fd, &wfx->bitrate);
530                         wfx->bitrate *= 8;
531                         read_uint16le(fd, &wfx->blockalign);
532                         read_uint16le(fd, &wfx->bitspersample);
533                         read_uint16le(fd, &wfx->datalen);
534 
535                         if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
536                             deadbeef->fread(wfx->data, 4, 1, fd);
537                             SKIP_BYTES(fd,current.size - 24 - 72 - 4);
538                             wfx->audiostream = flags&0x7f;
539                         } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
540                             deadbeef->fread(wfx->data, 6, 1, fd);
541                             SKIP_BYTES(fd,current.size - 24 - 72 - 6);
542                             wfx->audiostream = flags&0x7f;
543                         } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) {
544                             /* wma pro decoder needs the extra-data */
545                             deadbeef->fread(wfx->data, wfx->datalen, 1, fd);
546                             SKIP_BYTES(fd,current.size - 24 - 72 - wfx->datalen);
547                             wfx->audiostream = flags&0x7f;
548                             /* Correct codectype to redirect playback to the proper .codec */
549                             codectype = AFMT_WMAPRO;
550                         } else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) {
551                             deadbeef->fread(wfx->data, wfx->datalen, 1, fd);
552                             SKIP_BYTES(fd,current.size - 24 - 72 - wfx->datalen);
553                             wfx->audiostream = flags&0x7f;
554                             codectype = AFMT_WMAVOICE;
555                         } else {
556                             trace("Unsupported WMA codec (Lossless, Voice, etc)\n");
557                             SKIP_BYTES(fd,current.size - 24 - 72);
558                         }
559                     }
560             } else if (it && asf_guid_match(&current.guid, &asf_guid_content_description)) {
561                     /* Object contains five 16-bit string lengths, followed by the five strings:
562                        title, artist, copyright, description, rating
563                      */
564                     uint16_t strlength[5];
565                     int i;
566 
567                     DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));
568 
569                     /* Read the 5 string lengths - number of bytes included trailing zero */
570                     for (i=0; i<5; i++) {
571                         read_uint16le(fd, &strlength[i]);
572                         DEBUGF("strlength = %u\n",strlength[i]);
573                     }
574 
575                     if (strlength[0] > 0) {  /* 0 - Title */
576                         unsigned char *s = id3buf;
577                         asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
578                         deadbeef->pl_append_meta (it, "title", s);
579                     }
580 
581                     if (strlength[1] > 0) {  /* 1 - Artist */
582                         unsigned char *s = id3buf;
583                         asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
584                         deadbeef->pl_append_meta (it, "artist", s);
585                     }
586 
587                     SKIP_BYTES(fd, strlength[2]); /* 2 - copyright */
588 
589                     if (strlength[3] > 0) {  /* 3 - description */
590                         unsigned char *s = id3buf;
591                         asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
592                         deadbeef->pl_append_meta (it, "comment", s);
593                     }
594 
595                     SKIP_BYTES(fd, strlength[4]); /* 4 - rating */
596             } else if (it && asf_guid_match(&current.guid, &asf_guid_extended_content_description)) {
597                     uint16_t count;
598                     int i;
599                     int bytesleft = current.size - 24;
600                     DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");
601 
602                     read_uint16le(fd, &count);
603                     bytesleft -= 2;
604                     DEBUGF("extended metadata count = %u\n",count);
605 
606                     for (i=0; i < count; i++) {
607                         uint16_t length, type;
608                         unsigned char* utf8 = utf8buf;
609                         int utf8length = 512;
610 
611                         read_uint16le(fd, &length);
612                         asf_utf16LEdecode(fd, length, &utf8, &utf8length);
613                         bytesleft -= 2 + length;
614 
615                         read_uint16le(fd, &type);
616                         read_uint16le(fd, &length);
617                         trace ("ext md id: %s\n", utf8buf);
618 
619                         if (!strcmp("WM/TrackNumber",utf8buf) || !strcmp("WM/Track",utf8buf)) {
620                             if (type == 0) {
621                                 unsigned char *s = id3buf;
622                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
623                                 deadbeef->pl_append_meta (it, "track", s);
624                             } else if ((type >=2) && (type <= 5)) {
625                                 int tracknum = asf_intdecode(fd, type, length);
626                                 char n[100];
627                                 snprintf (n, sizeof (n), "%d", tracknum);
628                                 deadbeef->pl_append_meta (it, "track", n);
629                             } else {
630                                 SKIP_BYTES(fd, length);
631                             }
632                         } else if (!strcmp("TotalTracks",utf8buf)) {
633                             if (type == 0) {
634                                 unsigned char *s = id3buf;
635                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
636                                 deadbeef->pl_append_meta (it, "numtracks", s);
637                             } else if ((type >=2) && (type <= 5)) {
638                                 int tracknum = asf_intdecode(fd, type, length);
639                                 char n[100];
640                                 snprintf (n, sizeof (n), "%d", tracknum);
641                                 deadbeef->pl_append_meta (it, "numtracks", n);
642                             } else {
643                                 SKIP_BYTES(fd, length);
644                             }
645                         } else if (!strcmp("WM/PartOfSet",utf8buf)) {
646                             if (type == 0) {
647                                 unsigned char *s = id3buf;
648                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
649                                 asf_add_disc_meta (it, s);
650                             } else if ((type >=2) && (type <= 5)) {
651                                 int num = asf_intdecode(fd, type, length);
652                                 char n[100];
653                                 snprintf (n, sizeof (n), "%d", num);
654                                 deadbeef->pl_replace_meta (it, "disc", n);
655                             } else {
656                                 SKIP_BYTES(fd, length);
657                             }
658                         } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
659                             unsigned char *s = id3buf;
660                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
661                             deadbeef->pl_append_meta (it, "genre", s);
662                         } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
663                             unsigned char *s = id3buf;
664                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
665                             deadbeef->pl_append_meta (it, "album", s);
666                         } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
667                             unsigned char *s = id3buf;
668                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
669                             deadbeef->pl_append_meta (it, "albumartist", s);
670                         } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
671                             unsigned char *s = id3buf;
672                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
673                             deadbeef->pl_append_meta (it, "composer", s);
674                         } else if ((!strcasecmp("foobar2000/cuesheet", utf8buf)) && (type == 0)) {
675                             unsigned char *s = id3buf;
676                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
677                             deadbeef->pl_append_meta (it, "cuesheet", s);
678                         } else if (!strcmp("WM/Year", utf8buf)) {
679                             if (type == 0) {
680                                 unsigned char *s = id3buf;
681                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
682                                 deadbeef->pl_append_meta (it, "year", s);
683                             } else if ((type >=2) && (type <= 5)) {
684                                 int year = asf_intdecode(fd, type, length);
685                                 char n[100];
686                                 snprintf (n, sizeof (n), "%d", year);
687                                 deadbeef->pl_append_meta (it, "year", n);
688                             } else {
689                                 SKIP_BYTES(fd, length);
690                             }
691                         } else if (!strcmp("WM/OriginalReleaseYear", utf8buf)) {
692                             if (type == 0) {
693                                 unsigned char *s = id3buf;
694                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
695                                 deadbeef->pl_append_meta (it, "original_release_year", s);
696                             } else if ((type >=2) && (type <= 5)) {
697                                 int year = asf_intdecode(fd, type, length);
698                                 char n[100];
699                                 snprintf (n, sizeof (n), "%d", year);
700                                 deadbeef->pl_append_meta (it, "original_release_year", n);
701                             } else {
702                                 SKIP_BYTES(fd, length);
703                             }
704                         } else if (!strcmp("WM/OriginalReleaseTime", utf8buf)) {
705                             if (type == 0) {
706                                 unsigned char *s = id3buf;
707                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
708                                 deadbeef->pl_append_meta (it, "original_release_time", s);
709                             } else if ((type >=2) && (type <= 5)) {
710                                 int date = asf_intdecode(fd, type, length);
711                                 char n[100];
712                                 snprintf (n, sizeof (n), "%d", date);
713                                 deadbeef->pl_append_meta (it, "original_release_time", n);
714                             } else {
715                                 SKIP_BYTES(fd, length);
716                             }
717                         } else if (!strncmp("replaygain_", utf8buf, 11)) {
718                             char *s = utf8buf;
719                             char *value = id3buf;
720                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
721                             // parse_replaygain(utf8buf, value, id3);
722                             if (!strncasecmp (s, "replaygain_album_gain", 21)) {
723                                 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (value));
724                             }
725                             else if (!strncasecmp (s, "replaygain_album_peak", 21)) {
726                                 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (value));
727                             }
728                             else if (!strncasecmp (s, "replaygain_track_gain", 21)) {
729                                 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (value));
730                             }
731                             else if (!strncasecmp (s, "replaygain_track_peak", 21)) {
732                                 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (value));
733                             }
734                         } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
735                             unsigned char *s = id3buf;
736                             asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
737                             deadbeef->pl_append_meta (it, "MusicBrainzId", s);
738 #ifdef HAVE_ALBUMART
739                         } else if (!strcmp("WM/Picture", utf8buf)) {
740                             uint32_t datalength, strlength;
741                             /* Expected is either "01 00 xx xx 03 yy yy yy yy" or
742                              * "03 yy yy yy yy". xx is the size of the WM/Picture
743                              * container in bytes. yy equals the raw data length of
744                              * the embedded image. */
745                             SKIP_BYTES(fd, -4);
746                             deadbeef->fread(&type, 1, 1, fd);
747                             if (type == 1) {
748                                 SKIP_BYTES(fd, 3);
749                                 deadbeef->fread(&type, 1, 1, fd);
750                                 /* In case the parsing will fail in the next step we
751                                  * might at least be able to skip the whole section. */
752                                 datalength = length - 1;
753                             }
754                             if (type == 3) {
755                                 /* Read the raw data length of the embedded image. */
756                                 read_uint32le(fd, &datalength);
757 
758                                 /* Reset utf8 buffer */
759                                 utf8 = utf8buf;
760                                 utf8length = 512;
761 
762                                 /* Gather the album art format, this string has a
763                                  * double zero-termination. */
764                                 asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
765                                 strlength = (strlen(utf8buf) + 2) * 2;
766                                 SKIP_BYTES(fd, strlength-32);
767                                 if (!strcmp("image/jpeg", utf8buf)) {
768                                     id3->albumart.type = AA_TYPE_JPG;
769                                 } else if (!strcmp("image/jpg", utf8buf)) {
770                                     /* image/jpg is technically invalid,
771                                      * but it does occur in the wild */
772                                     id3->albumart.type = AA_TYPE_JPG;
773                                 } else if (!strcmp("image/png", utf8buf)) {
774                                     id3->albumart.type = AA_TYPE_PNG;
775                                 } else {
776                                     id3->albumart.type = AA_TYPE_UNKNOWN;
777                                 }
778 
779                                 /* Set the album art size and position. */
780                                 if (id3->albumart.type != AA_TYPE_UNKNOWN) {
781                                     id3->albumart.pos  = SKIP_BYTES(fd, 0);
782                                     id3->albumart.size = datalength;
783                                     id3->has_embedded_albumart = true;
784                                 }
785                             }
786 
787                             SKIP_BYTES(fd, datalength);
788 #endif
789                         } else {
790                             if (type == 0) { // FIXME: custom fields -- after others work
791                                 unsigned char *s = id3buf;
792                                 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
793                                 if (!strcmp (utf8buf, "MusicBrainz/Track Id")) {
794                                     strcpy (utf8buf, "musicbrainz_trackid");
795                                 }
796                                 deadbeef->pl_append_meta (it, utf8buf, s);
797                             }
798                             else {
799                                 SKIP_BYTES(fd, length);
800                             }
801                         }
802                         bytesleft -= 4 + length;
803                     }
804 
805                     SKIP_BYTES(fd, bytesleft);
806             } else if (asf_guid_match(&current.guid, &asf_guid_content_encryption)
807                 || asf_guid_match(&current.guid, &asf_guid_extended_content_encryption)) {
808                 DEBUGF("File is encrypted\n");
809                 return ASF_ERROR_ENCRYPTED;
810             } else {
811                 DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
812                 SKIP_BYTES(fd,current.size - 24);
813             }
814 
815             DEBUGF("Parsed object - size = %d\n",(int)current.size);
816             datalen -= current.size;
817         }
818 
819         if (i != (int)subobjects || datalen != 0) {
820             DEBUGF("header data doesn't match given subobject count\n");
821             return ASF_ERROR_INVALID_VALUE;
822         }
823 
824         DEBUGF("%d subobjects read successfully\n", i);
825     }
826 
827 #if 0
828     tmp = asf_parse_header_validate(file, &header);
829     if (tmp < 0) {
830         /* header read ok but doesn't validate correctly */
831         return tmp;
832     }
833 #endif
834 
835     DEBUGF("header validated correctly\n");
836 
837     return 0;
838 }
839 
get_asf_metadata(DB_FILE * fd,DB_playItem_t * it,asf_waveformatex_t * wfx,int64_t * first_frame_offset)840 int get_asf_metadata(DB_FILE *fd, DB_playItem_t *it, asf_waveformatex_t *wfx, int64_t *first_frame_offset)
841 {
842     int res;
843     asf_object_t obj;
844 
845     wfx->audiostream = -1;
846 
847     res = asf_parse_header(fd, wfx, it);
848 
849     if (res < 0) {
850         DEBUGF("ASF: parsing error - %d\n",res);
851         return 0;
852     }
853 
854     if (wfx->audiostream == -1) {
855         DEBUGF("ASF: No WMA streams found\n");
856         return 0;
857     }
858 
859     asf_read_object_header(&obj, fd);
860 
861     if (!asf_guid_match(&obj.guid, &asf_guid_data)) {
862         DEBUGF("ASF: No data object found\n");
863         return 0;
864     }
865 
866     /* Store the current file position - no need to parse the header
867        again in the codec.  The +26 skips the rest of the data object
868        header.
869      */
870     *first_frame_offset = deadbeef->ftell(fd) + 26;
871 
872     if (!fd->vfs->is_streaming ()) {
873         // check if we got a fragment
874         if (0 != deadbeef->fseek (fd, 26, SEEK_CUR)) {
875             DEBUGF("ASF: failed to seek to 1st frame\n");
876             return 0;
877         }
878         int duration = 0;
879         int time = asf_get_timestamp(&duration, fd);
880         if (time != 0) {
881             wfx->first_frame_timestamp = time;
882             // need to scan entire file to find out the duration
883             int pmn = (int)(time * 0.001f / 60);
884             int psc = time * 0.001f - pmn * 60;
885             trace ("wma: the file is a fragment, start time: %d:%02d\n", pmn, psc);
886             trace ("play_duration %lld, numpackets %lld, packet_size %d\n",  wfx->play_duration, wfx->numpackets, wfx->packet_size);
887         }
888         if (wfx->play_duration == 0) {
889             wfx->preroll = 0;
890             wfx->numpackets = 1;
891             // calc duration from packets (scan the file)
892             wfx->play_duration += duration * 10000;
893             while (0 == deadbeef->fseek (fd, *first_frame_offset + wfx->packet_size * wfx->numpackets, SEEK_SET)) {
894                 time = asf_get_timestamp(&duration, fd);
895                 if (time < 0) {
896                     break;
897                 }
898                 wfx->play_duration += duration * 10000;
899                 wfx->numpackets++;
900             }
901         }
902     }
903 
904     return 1;
905 }
906