Example #1
0
unsigned stats_get_version(char *type, uint8_t *data){
    /* I could've used iff_parse_chunk instead to determine chunk versions, but this
       would be unnecessarily slow and would require all chunk parsers to be written,
       defeating the purpose of this tool. */

    if(!strcmp(type, "STR#") || !strcmp(type, "CTSS") || !strcmp(type, "FAMs") ||
       !strcmp(type, "TTAs") || !strcmp(type, "CST")  || !strcmp(type, "BHAV") ||
       !strcmp(type, "DGRP") || !strcmp(type, "POSI"))
        return read_uint16le(data);

    if(!strcmp(type, "FCNS") || !strcmp(type, "OBJf") || !strcmp(type, "Optn") ||
       !strcmp(type, "Rcon") || !strcmp(type, "TPRP") || !strcmp(type, "SLOT") ||
       !strcmp(type, "TRCN") || !strcmp(type, "rsmp"))
        return read_uint32le(data+4);

    if(!strcmp(type, "OBJD") || !strcmp(type, "PALT") || !strcmp(type, "SPR2"))
        return read_uint32le(data);

    if(!strcmp(type, "TTAB"))
        return read_uint16le(data+2);

    if(!strcmp(type, "SPR#")){
        if(data[0] == 0) return read_uint32be(data);
        else return read_uint32le(data);
    }

    return -1;
}
Example #2
0
/* Read the 16 byte GUID from a file */
static void asf_readGUID(int fd, guid_t* guid)
{
    read_uint32le(fd, &guid->v1);
    read_uint16le(fd, &guid->v2);
    read_uint16le(fd, &guid->v3);
    read(fd, guid->v4, 8);
}
Example #3
0
/* Parse an integer from the extended content object - we always
   convert to an int, regardless of native format.
*/
static int asf_intdecode(int fd, int type, int length)
{
    uint16_t tmp16;
    uint32_t tmp32;
    uint64_t tmp64;

    if (type == 3) {
        read_uint32le(fd, &tmp32);
        lseek(fd,length - 4,SEEK_CUR);
        return (int)tmp32;
    } else if (type == 4) {
        read_uint64le(fd, &tmp64);
        lseek(fd,length - 8,SEEK_CUR);
        return (int)tmp64;
    } else if (type == 5) {
        read_uint16le(fd, &tmp16);
        lseek(fd,length - 2,SEEK_CUR);
        return (int)tmp16;
    }

    return 0;
}
Example #4
0
static int asf_parse_header(int fd, struct mp3entry* id3,
                                    asf_waveformatex_t* wfx)
{
    asf_object_t current;
    asf_object_t header;
    uint64_t datalen;
    int i;
    int fileprop = 0;
    uint64_t play_duration;
    uint16_t flags;
    uint32_t subobjects;
    uint8_t utf8buf[512];
    int id3buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
    unsigned char* id3buf = (unsigned char*)id3->id3v2buf;

    asf_read_object_header((asf_object_t *) &header, fd);

    //DEBUGF("header.size=%d\n",(int)header.size);
    if (header.size < 30) {
        /* invalid size for header object */
        return ASF_ERROR_OBJECT_SIZE;
    }

    read_uint32le(fd, &subobjects);

    /* Two reserved bytes - do we need to read them? */
    lseek(fd, 2, SEEK_CUR);

    //DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);

    if (subobjects > 0) {
        header.datalen = header.size - 30;

        /* TODO: Check that we have datalen bytes left in the file */
        datalen = header.datalen;

        for (i=0; i<(int)subobjects; i++) {
            //DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
            if (datalen < 24) {
                //DEBUGF("not enough data for reading object\n");
                break;
            }

            asf_read_object_header(&current, fd);

            if (current.size > datalen || current.size < 24) {
                //DEBUGF("invalid object size - current.size=%d, datalen=%d\n",(int)current.size,(int)datalen);
                break;
            }

            if (asf_guid_match(&current.guid, &asf_guid_file_properties)) {
                    if (current.size < 104)
                        return ASF_ERROR_OBJECT_SIZE;

                    if (fileprop) {
                        /* multiple file properties objects not allowed */
                        return ASF_ERROR_INVALID_OBJECT;
                    }

                    fileprop = 1;
                    
                    /* Get the number of logical packets - uint64_t at offset 32
                     * (little endian byte order) */
                    lseek(fd, 32, SEEK_CUR);
                    read_uint64le(fd, &wfx->numpackets);
                    /*DEBUGF("read packets:  %llx %lld\n", wfx->numpackets, wfx->numpackets);*/
                    
                    /* Now get the play duration - uint64_t at offset 40 */
                    read_uint64le(fd, &play_duration);
                    id3->length = play_duration / 10000;
                    /*DEBUGF("****** length = %lums\n", id3->length);*/

                    /* Read the packet size - uint32_t at offset 68 */
                    lseek(fd, 20, SEEK_CUR);
                    read_uint32le(fd, &wfx->packet_size);

                    /* Skip bytes remaining in object */
                    lseek(fd, current.size - 24 - 72, SEEK_CUR);
            } else if (asf_guid_match(&current.guid, &asf_guid_stream_properties)) {
                    guid_t guid;
                    uint32_t propdatalen;

                    if (current.size < 78)
                        return ASF_ERROR_OBJECT_SIZE;

#if 0
                    asf_byteio_getGUID(&guid, current->data);
                    datalen = asf_byteio_getDWLE(current->data + 40);
                    flags = asf_byteio_getWLE(current->data + 48);
#endif

                    asf_readGUID(fd, &guid);

                    lseek(fd, 24, SEEK_CUR);
                    read_uint32le(fd, &propdatalen);
                    lseek(fd, 4, SEEK_CUR);
                    read_uint16le(fd, &flags);

                    if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
                        //DEBUGF("Found stream properties for non audio stream, skipping\n");
                        lseek(fd,current.size - 24 - 50,SEEK_CUR);
                    } else if (wfx->audiostream == -1) {
                        lseek(fd, 4, SEEK_CUR);
                        //DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);

                        if (propdatalen < 18) {
                            return ASF_ERROR_INVALID_LENGTH;
                        }

#if 0
                        if (asf_byteio_getWLE(data + 16) > datalen - 16) {
                            return ASF_ERROR_INVALID_LENGTH;
                        }
#endif
                        read_uint16le(fd, &wfx->codec_id);
                        read_uint16le(fd, &wfx->channels);
                        read_uint32le(fd, &wfx->rate);
                        read_uint32le(fd, &wfx->bitrate);
                        wfx->bitrate *= 8;
                        read_uint16le(fd, &wfx->blockalign);
                        read_uint16le(fd, &wfx->bitspersample);
                        read_uint16le(fd, &wfx->datalen);

                        /*sanity check the included bitrate by comparing to file size and length*/
                        unsigned int estimated_bitrate =  (wfx->packet_size*wfx->numpackets)/id3->length*8000;

                        /*in theory we could just use the estimated bitrate always,
                          but its safer to underestimate*/
                        if( wfx->bitrate > estimated_bitrate)
                        {
                            /* Round bitrate to the nearest kbit */
                            id3->bitrate = (estimated_bitrate + 500) / 1000;
                        }
                        else
                        {
                            /* Round bitrate to the nearest kbit */
                            id3->bitrate = (wfx->bitrate + 500) / 1000;
                        }
                        /*DEBUGF("bitrate:  %d estimated:  %d\n", wfx->bitrate, estimated_bitrate);*/
                        id3->frequency = wfx->rate;

                        if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
                            read(fd, wfx->data, 4);
                            lseek(fd,current.size - 24 - 72 - 4,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                        } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
                            read(fd, wfx->data, 6);
                            lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                        } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) {
                            /* wma pro decoder needs the extra-data */
                            read(fd, wfx->data, wfx->datalen);
                            lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                            /* Correct codectype to redirect playback to the proper .codec */
                            id3->codectype = AFMT_WMAPRO;
                        } else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) {
                            read(fd, wfx->data, wfx->datalen);
                            lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                            id3->codectype = AFMT_WMAVOICE;
                        } else {
                            DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
                            lseek(fd,current.size - 24 - 72,SEEK_CUR);
                        }

                    }
            } else if (asf_guid_match(&current.guid, &asf_guid_content_description)) {
                    /* Object contains five 16-bit string lengths, followed by the five strings:
                       title, artist, copyright, description, rating
                     */
                    uint16_t strlength[5];
                    int i;

                    //DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));

                    /* Read the 5 string lengths - number of bytes included trailing zero */
                    for (i=0; i<5; i++) {
                        read_uint16le(fd, &strlength[i]);
                        //DEBUGF("strlength = %u\n",strlength[i]);
                    }

                    if (strlength[0] > 0) {  /* 0 - Title */
                        id3->title = id3buf;
                        asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
                    }

                    if (strlength[1] > 0) {  /* 1 - Artist */
                        id3->artist = id3buf;
                        asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
                    }

                    lseek(fd, strlength[2], SEEK_CUR); /* 2 - copyright */

                    if (strlength[3] > 0) {  /* 3 - description */
                        id3->comment = id3buf;
                        asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
                    }

                    lseek(fd, strlength[4], SEEK_CUR); /* 4 - rating */
            } else if (asf_guid_match(&current.guid, &asf_guid_extended_content_description)) {
                    uint16_t count;
                    int i;
                    int bytesleft = current.size - 24;
                    //DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");

                    read_uint16le(fd, &count);
                    bytesleft -= 2;
                    //DEBUGF("extended metadata count = %u\n",count);

                    for (i=0; i < count; i++) {
                        uint16_t length, type;
                        unsigned char* utf8 = utf8buf;
                        int utf8length = 512;

                        read_uint16le(fd, &length);
                        asf_utf16LEdecode(fd, length, &utf8, &utf8length);
                        bytesleft -= 2 + length;

                        read_uint16le(fd, &type);
                        read_uint16le(fd, &length);

                        if (!strcmp("WM/TrackNumber",utf8buf)) {
                            if (type == 0) {
                                id3->track_string = id3buf;
                                asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                                id3->tracknum = atoi(id3->track_string);
                            } else if ((type >=2) && (type <= 5)) {
                                id3->tracknum = asf_intdecode(fd, type, length);
                            } else {
                                lseek(fd, length, SEEK_CUR);
                            }
                        } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
                            id3->genre_string = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
                            id3->album = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
                            id3->albumartist = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
                            id3->composer = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if (!strcmp("WM/Year", utf8buf)) {
                            if (type == 0) {
                                id3->year_string = id3buf;
                                asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                                id3->year = atoi(id3->year_string);
                            } else if ((type >=2) && (type <= 5)) {
                                id3->year = asf_intdecode(fd, type, length);
                            } else {
                                lseek(fd, length, SEEK_CUR);
                            }
                        } else if (!strncmp("replaygain_", utf8buf, 11)) {
                            char *value = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                            parse_replaygain(utf8buf, value, id3);
                        } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
                            id3->mb_track_id = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
#ifdef HAVE_ALBUMART
                        } else if (!strcmp("WM/Picture", utf8buf)) {
                            uint32_t datalength, strlength;
                            /* Expected is either "01 00 xx xx 03 yy yy yy yy" or
                             * "03 yy yy yy yy". xx is the size of the WM/Picture 
                             * container in bytes. yy equals the raw data length of 
                             * the embedded image. */
                            lseek(fd, -4, SEEK_CUR);
                            read(fd, &type, 1);
                            if (type == 1) {
                                lseek(fd, 3, SEEK_CUR);
                                read(fd, &type, 1);
                                /* In case the parsing will fail in the next step we 
                                 * might at least be able to skip the whole section. */
                                datalength = length - 1;
                            }
                            if (type == 3) {
                                /* Read the raw data length of the embedded image. */
                                read_uint32le(fd, &datalength);
                            
                                /* Reset utf8 buffer */
                                utf8 = utf8buf;
                                utf8length = 512;

                                /* Gather the album art format, this string has a
                                 * double zero-termination. */
                                asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
                                strlength = (strlen(utf8buf) + 2) * 2;
                                lseek(fd, strlength-32, SEEK_CUR);
                                if (!strcmp("image/jpeg", utf8buf)) {
                                    id3->albumart.type = AA_TYPE_JPG;
                                } else if (!strcmp("image/jpg", utf8buf)) {
                                    /* image/jpg is technically invalid,
                                     * but it does occur in the wild */
                                    id3->albumart.type = AA_TYPE_JPG;
                                } else if (!strcmp("image/png", utf8buf)) {
                                    id3->albumart.type = AA_TYPE_PNG;
                                } else {
                                    id3->albumart.type = AA_TYPE_UNKNOWN;
                                }

                                /* Set the album art size and position. */
                                if (id3->albumart.type != AA_TYPE_UNKNOWN) {
                                    id3->albumart.pos  = lseek(fd, 0, SEEK_CUR);
                                    id3->albumart.size = datalength;
                                    id3->has_embedded_albumart = true;
                                }
                            }
                            
                            lseek(fd, datalength, SEEK_CUR);
#endif
                        } else {
                            lseek(fd, length, SEEK_CUR);
                        }
                        bytesleft -= 4 + length;
                    }

                    lseek(fd, bytesleft, SEEK_CUR);
            } else if (asf_guid_match(&current.guid, &asf_guid_content_encryption)
                || asf_guid_match(&current.guid, &asf_guid_extended_content_encryption)) {
                //DEBUGF("File is encrypted\n");
                return ASF_ERROR_ENCRYPTED;
            } else {
                //DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
                lseek(fd,current.size - 24,SEEK_CUR);
            }

            //DEBUGF("Parsed object - size = %d\n",(int)current.size);
            datalen -= current.size;
        }

        if (i != (int)subobjects || datalen != 0) {
            //DEBUGF("header data doesn't match given subobject count\n");
            return ASF_ERROR_INVALID_VALUE;
        }

        //DEBUGF("%d subobjects read successfully\n", i);
    }

#if 0
    tmp = asf_parse_header_validate(file, &header);
    if (tmp < 0) {
        /* header read ok but doesn't validate correctly */
        return tmp;
    }
#endif

    //DEBUGF("header validated correctly\n");

    return 0;
}
Example #5
0
static int asf_parse_header(int fd, struct mp3entry* id3,
                                    asf_waveformatex_t* wfx)
{
    asf_object_t current;
    asf_object_t header;
    uint64_t datalen;
    int i;
    int fileprop = 0;
    uint64_t play_duration;
    uint16_t flags;
    uint32_t subobjects;
    uint8_t utf8buf[512];
    int id3buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
    unsigned char* id3buf = (unsigned char*)id3->id3v2buf;

    asf_read_object_header((asf_object_t *) &header, fd);

    //DEBUGF("header.size=%d\n",(int)header.size);
    if (header.size < 30) {
        /* invalid size for header object */
        return ASF_ERROR_OBJECT_SIZE;
    }

    read_uint32le(fd, &subobjects);

    /* Two reserved bytes - do we need to read them? */
    lseek(fd, 2, SEEK_CUR);

    //DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);

    if (subobjects > 0) {
        header.datalen = header.size - 30;

        /* TODO: Check that we have datalen bytes left in the file */
        datalen = header.datalen;

        for (i=0; i<(int)subobjects; i++) {
            //DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
            if (datalen < 24) {
                //DEBUGF("not enough data for reading object\n");
                break;
            }

            asf_read_object_header(&current, fd);

            if (current.size > datalen || current.size < 24) {
                //DEBUGF("invalid object size - current.size=%d, datalen=%d\n",(int)current.size,(int)datalen);
                break;
            }

            if (asf_guid_match(&current.guid, &asf_guid_file_properties)) {
                    if (current.size < 104)
                        return ASF_ERROR_OBJECT_SIZE;

                    if (fileprop) {
                        /* multiple file properties objects not allowed */
                        return ASF_ERROR_INVALID_OBJECT;
                    }

                    fileprop = 1;
                    
                    /* Get the number of logical packets - uint16_t at offset 31 
                     * (Big endian byte order) */
                    lseek(fd, 31, SEEK_CUR);
                    read_uint16be(fd, &wfx->numpackets);
                    
                    /* Now get the play duration - uint64_t at offset 40 */
                    lseek(fd, 7, SEEK_CUR);
                    read_uint64le(fd, &play_duration);
                    id3->length = play_duration / 10000;

                    //DEBUGF("****** length = %lums\n", id3->length);

                    /* Read the packet size - uint32_t at offset 68 */
                    lseek(fd, 20, SEEK_CUR);
                    read_uint32le(fd, &wfx->packet_size);

                    /* Skip bytes remaining in object */
                    lseek(fd, current.size - 24 - 72, SEEK_CUR);
            } else if (asf_guid_match(&current.guid, &asf_guid_stream_properties)) {
                    guid_t guid;
                    uint32_t propdatalen;

                    if (current.size < 78)
                        return ASF_ERROR_OBJECT_SIZE;

#if 0
                    asf_byteio_getGUID(&guid, current->data);
                    datalen = asf_byteio_getDWLE(current->data + 40);
                    flags = asf_byteio_getWLE(current->data + 48);
#endif

                    asf_readGUID(fd, &guid);

                    lseek(fd, 24, SEEK_CUR);
                    read_uint32le(fd, &propdatalen);
                    lseek(fd, 4, SEEK_CUR);
                    read_uint16le(fd, &flags);

                    if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
                        //DEBUGF("Found stream properties for non audio stream, skipping\n");
                        lseek(fd,current.size - 24 - 50,SEEK_CUR);
                    } else if (wfx->audiostream == -1) {
                        lseek(fd, 4, SEEK_CUR);
                        //DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);

                        if (propdatalen < 18) {
                            return ASF_ERROR_INVALID_LENGTH;
                        }

#if 0
                        if (asf_byteio_getWLE(data + 16) > datalen - 16) {
                            return ASF_ERROR_INVALID_LENGTH;
                        }
#endif
                        read_uint16le(fd, &wfx->codec_id);
                        read_uint16le(fd, &wfx->channels);
                        read_uint32le(fd, &wfx->rate);
                        read_uint32le(fd, &wfx->bitrate);
                        wfx->bitrate *= 8;
                        read_uint16le(fd, &wfx->blockalign);
                        read_uint16le(fd, &wfx->bitspersample);
                        read_uint16le(fd, &wfx->datalen);

                        /* Round bitrate to the nearest kbit */
                        id3->bitrate = (wfx->bitrate + 500) / 1000;
                        id3->frequency = wfx->rate;

                        if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
                            read(fd, wfx->data, 4);
                            lseek(fd,current.size - 24 - 72 - 4,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                        } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
                            read(fd, wfx->data, 6);
                            lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                        } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) {
                            /* wma pro decoder needs the extra-data */
                            read(fd, wfx->data, wfx->datalen);
                            lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
                            wfx->audiostream = flags&0x7f;
                            /* Correct codectype to redirect playback to the proper .codec */
                            id3->codectype = AFMT_WMAPRO;
                        } else {
                            DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
                            lseek(fd,current.size - 24 - 72,SEEK_CUR);
                        }

                    }
            } else if (asf_guid_match(&current.guid, &asf_guid_content_description)) {
                    /* Object contains five 16-bit string lengths, followed by the five strings:
                       title, artist, copyright, description, rating
                     */
                    uint16_t strlength[5];
                    int i;

                    //DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));

                    /* Read the 5 string lengths - number of bytes included trailing zero */
                    for (i=0; i<5; i++) {
                        read_uint16le(fd, &strlength[i]);
                        //DEBUGF("strlength = %u\n",strlength[i]);
                    }

                    if (strlength[0] > 0) {  /* 0 - Title */
                        id3->title = id3buf;
                        asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
                    }

                    if (strlength[1] > 0) {  /* 1 - Artist */
                        id3->artist = id3buf;
                        asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
                    }

                    lseek(fd, strlength[2], SEEK_CUR); /* 2 - copyright */

                    if (strlength[3] > 0) {  /* 3 - description */
                        id3->comment = id3buf;
                        asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
                    }

                    lseek(fd, strlength[4], SEEK_CUR); /* 4 - rating */
            } else if (asf_guid_match(&current.guid, &asf_guid_extended_content_description)) {
                    uint16_t count;
                    int i;
                    int bytesleft = current.size - 24;
                    //DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");

                    read_uint16le(fd, &count);
                    bytesleft -= 2;
                    //DEBUGF("extended metadata count = %u\n",count);

                    for (i=0; i < count; i++) {
                        uint16_t length, type;
                        unsigned char* utf8 = utf8buf;
                        int utf8length = 512;

                        read_uint16le(fd, &length);
                        asf_utf16LEdecode(fd, length, &utf8, &utf8length);
                        bytesleft -= 2 + length;

                        read_uint16le(fd, &type);
                        read_uint16le(fd, &length);

                        if (!strcmp("WM/TrackNumber",utf8buf)) {
                            if (type == 0) {
                                id3->track_string = id3buf;
                                asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                                id3->tracknum = atoi(id3->track_string);
                            } else if ((type >=2) && (type <= 5)) {
                                id3->tracknum = asf_intdecode(fd, type, length);
                            } else {
                                lseek(fd, length, SEEK_CUR);
                            }
                        } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
                            id3->genre_string = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
                            id3->album = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
                            id3->albumartist = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
                            id3->composer = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else if (!strcmp("WM/Year", utf8buf)) {
                            if (type == 0) {
                                id3->year_string = id3buf;
                                asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                                id3->year = atoi(id3->year_string);
                            } else if ((type >=2) && (type <= 5)) {
                                id3->year = asf_intdecode(fd, type, length);
                            } else {
                                lseek(fd, length, SEEK_CUR);
                            }
                        } else if (!strncmp("replaygain_", utf8buf, 11)) {
                            char* value = id3buf;
                            int buf_len = id3buf_remaining;
                            int len;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                            len = parse_replaygain(utf8buf, value, id3, 
                                value, buf_len);
                            
                            if (len == 0) {
                                /* Don't need to keep the value */
                                id3buf = value;
                                id3buf_remaining = buf_len;
                            }
                        } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
                            id3->mb_track_id = id3buf;
                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
                        } else {
                            lseek(fd, length, SEEK_CUR);
                        }
                        bytesleft -= 4 + length;
                    }

                    lseek(fd, bytesleft, SEEK_CUR);
            } else if (asf_guid_match(&current.guid, &asf_guid_content_encryption)
                || asf_guid_match(&current.guid, &asf_guid_extended_content_encryption)) {
                //DEBUGF("File is encrypted\n");
                return ASF_ERROR_ENCRYPTED;
            } else {
                //DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
                lseek(fd,current.size - 24,SEEK_CUR);
            }

            //DEBUGF("Parsed object - size = %d\n",(int)current.size);
            datalen -= current.size;
        }

        if (i != (int)subobjects || datalen != 0) {
            //DEBUGF("header data doesn't match given subobject count\n");
            return ASF_ERROR_INVALID_VALUE;
        }

        //DEBUGF("%d subobjects read successfully\n", i);
    }

#if 0
    tmp = asf_parse_header_validate(file, &header);
    if (tmp < 0) {
        /* header read ok but doesn't validate correctly */
        return tmp;
    }
#endif

    //DEBUGF("header validated correctly\n");

    return 0;
}
Example #6
0
File: nsf.c Project: IlVerz/rockbox
static bool parse_nsfe(int fd, struct mp3entry *id3)
{
    unsigned int chunks_found = 0;
    long track_count = 0;
    long playlist_count = 0;

    struct NSFE_INFOCHUNK info;
    memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));

     /* default values */
    info.nTrackCount = 1;
    id3->length = 150 * 1000;
    
    /* begin reading chunks */
    while (!(chunks_found & CHUNK_NEND))
    {
        uint32_t chunk_size, chunk_type;

        if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
            return false;

        if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
            return false;

        switch (chunk_type)
        {
        /* first three types are mandatory (but don't worry about NEND
           anyway) */
        case CHAR4_CONST('I', 'N', 'F', 'O'):
        {
            if (chunks_found & CHUNK_INFO)
                return false; /* only one info chunk permitted */

            chunks_found |= CHUNK_INFO;

            /* minimum size */
            if (chunk_size < 8)
                return false;

            ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);

            if (read(fd, &info, size) != size)
                return false;

            if (size >= 9)
                track_count = info.nTrackCount;

            chunk_size -= size;
            break;
            }

        case CHAR4_CONST('D', 'A', 'T', 'A'):
        {
            if (!(chunks_found & CHUNK_INFO))
                return false;

            if (chunks_found & CHUNK_DATA)
                return false; /* only one may exist */

            if (chunk_size < 1)
                return false;

            chunks_found |= CHUNK_DATA;
            break;
            }

        case CHAR4_CONST('N', 'E', 'N', 'D'):
        {
            /* just end parsing regardless of whether or not this really is the
               last chunk/data (but it _should_ be) */
            chunks_found |= CHUNK_NEND;
            continue;
            }

        /* remaining types are optional */

        case CHAR4_CONST('a', 'u', 't', 'h'):
        {
            if (chunks_found & CHUNK_auth)
                return false; /* only one may exist */

            chunks_found |= CHUNK_auth;

            /* szGameTitle, szArtist, szCopyright */
            char ** const ar[] = { &id3->title, &id3->artist, &id3->album };

            char *p = id3->id3v2buf;
            long buf_rem = sizeof (id3->id3v2buf);
            unsigned int i;

            for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
            {
                long len = read_string(fd, p, buf_rem, '\0', chunk_size);

                if (len < 0)
                    return false;

                *ar[i] = p;
                p += len;
                buf_rem -= len;

                if (chunk_size >= (uint32_t)len)
                    chunk_size -= len;
                else
                    chunk_size = 0;
            }

            break;
            }

        case CHAR4_CONST('p', 'l', 's', 't'):
        {
            if (chunks_found & CHUNK_plst)
                return false; /* only one may exist */

            chunks_found |= CHUNK_plst;

            /* each byte is the index of one track */
            playlist_count = chunk_size;
            break;
            }

        case CHAR4_CONST('t', 'i', 'm', 'e'):
        case CHAR4_CONST('f', 'a', 'd', 'e'):
        case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
        {
            /* don't care how many of these there are even though there should
               be only one */
            if (!(chunks_found & CHUNK_INFO))
                return false;

        case CHAR4_CONST('B', 'A', 'N', 'K'):
            break;
            }

        default: /* unknown chunk */
        {
            /* check the first byte */
            chunk_type = (uint8_t)chunk_type;

            /* chunk is vital... don't continue */
            if(chunk_type >= 'A' && chunk_type <= 'Z')
                return false;

            /* otherwise, just skip it */
            break;
            }
        } /* end switch */

        lseek(fd, chunk_size, SEEK_CUR);
    } /* end while */

    if (track_count | playlist_count)
        id3->length = MAX(track_count, playlist_count)*1000;

    /* Single subtrack files will be treated differently
        by gme's nsf codec */
    if (id3->length <= 1000) id3->length = 150 * 1000;

    /*
     * if we exited the while loop without a 'return', we must have hit an NEND
     *  chunk if this is the case, the file was layed out as it was expected.
     *  now.. make sure we found both an info chunk, AND a data chunk... since
     *  these are minimum requirements for a valid NSFE file
     */
    return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
            (CHUNK_INFO | CHUNK_DATA);
}