Exemple #1
0
static gboolean decode_rva_block (const guchar * * _data, gint * _size, gint *
 channel, gint * adjustment, gint * adjustment_unit, gint * peak, gint *
 peak_unit)
{
    const guchar * data = * _data;
    gint size = * _size;
    gint peak_bits;

    if (size < 4)
        return FALSE;

    * channel = data[0];
    * adjustment = (gchar) data[1]; /* first byte is signed */
    * adjustment = (* adjustment << 8) | data[2];
    * adjustment_unit = 512;
    peak_bits = data[3];

    data += 4;
    size -= 4;

    TAGDBG ("RVA block: channel = %d, adjustment = %d/%d, peak bits = %d\n",
     * channel, * adjustment, * adjustment_unit, peak_bits);

    if (peak_bits > 0 && peak_bits < sizeof (gint) * 8)
    {
        gint bytes = (peak_bits + 7) / 8;
        gint count;

        if (bytes > size)
            return FALSE;

        * peak = 0;
        * peak_unit = 1 << peak_bits;

        for (count = 0; count < bytes; count ++)
            * peak = (* peak << 8) | data[count];

        data += bytes;
        size -= count;

        TAGDBG ("RVA block: peak = %d/%d\n", * peak, * peak_unit);
    }
    else
    {
        * peak = 0;
        * peak_unit = 0;
    }

    * _data = data;
    * _size = size;
    return TRUE;
}
Exemple #2
0
static gboolean read_header (VFSFile * handle, gint * version, gboolean *
 syncsafe, gsize * offset, gint * header_size, gint * data_size)
{
    ID3v2Header header;

    if (vfs_fseek (handle, 0, SEEK_SET))
        return FALSE;

    if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof
     (ID3v2Header))
        return FALSE;

    if (validate_header (& header))
    {
        * offset = 0;
        * version = header.version;
        * header_size = sizeof (ID3v2Header);
        * data_size = header.size;
    } else return FALSE;

    * syncsafe = (header.flags & ID3_HEADER_SYNCSAFE) ? TRUE : FALSE;

    TAGDBG ("Offset = %d, header size = %d, data size = %d\n",
     (gint) * offset, * header_size, * data_size);

    return TRUE;
}
Exemple #3
0
static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe,
 gint data_size, mowgli_dictionary_t * dict)
{
    gint pos;

    for (pos = 0; pos < data_size; )
    {
        gint frame_size, size;
        gchar key[5];
        guchar * data;
        GenericFrame * frame;

        if (! read_frame (handle, data_size - pos, version, syncsafe,
         & frame_size, key, & data, & size))
            break;

        pos += frame_size;

        if (mowgli_dictionary_retrieve (dict, key) != NULL)
        {
            TAGDBG ("Discarding duplicate frame %s.\n", key);
            g_free (data);
            continue;
        }

        frame = g_malloc (sizeof (GenericFrame));
        strcpy (frame->key, key);
        frame->data = data;
        frame->size = size;

        mowgli_dictionary_add (dict, key, frame);
    }
}
Exemple #4
0
static void decode_rva (Tuple * tuple, const guchar * data, gint size)
{
    const gchar * domain;
    gint channel, adjustment, adjustment_unit, peak, peak_unit;

    if (memchr (data, 0, size) == NULL)
        return;

    domain = (const gchar *) data;

    TAGDBG ("RVA domain: %s\n", domain);

    size -= strlen (domain) + 1;
    data += strlen (domain) + 1;

    while (size > 0)
    {
        if (! decode_rva_block (& data, & size, & channel, & adjustment,
         & adjustment_unit, & peak, & peak_unit))
            break;

        if (channel != 1) /* specific channel? */
            continue;

        if (tuple_get_value_type (tuple, FIELD_GAIN_GAIN_UNIT, NULL) ==
         TUPLE_INT)
            adjustment = adjustment * (gint64) tuple_get_int (tuple,
             FIELD_GAIN_GAIN_UNIT, NULL) / adjustment_unit;
        else
            tuple_associate_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL,
             adjustment_unit);

        if (peak_unit)
        {
            if (tuple_get_value_type (tuple, FIELD_GAIN_PEAK_UNIT, NULL) ==
             TUPLE_INT)
                peak = peak * (gint64) tuple_get_int (tuple,
                 FIELD_GAIN_PEAK_UNIT, NULL) / peak_unit;
            else
                tuple_associate_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL,
                 peak_unit);
        }

        if (! strcasecmp (domain, "album"))
        {
            tuple_associate_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL, adjustment);

            if (peak_unit)
                tuple_associate_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL, peak);
        }
        else if (! strcasecmp (domain, "track"))
        {
            tuple_associate_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL, adjustment);

            if (peak_unit)
                tuple_associate_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL, peak);
        }
    }
}
Exemple #5
0
static gint writeAllFramesToFile (VFSFile * fd, mowgli_dictionary_t * dict)
{
    WriteState state = {fd, 0};
    mowgli_dictionary_foreach (dict, write_frame_cb, & state);

    TAGDBG ("Total frame bytes written = %d.\n", state.written_size);
    return state.written_size;
}
Exemple #6
0
static int write_all_frames (VFSFile * handle, GHashTable * dict)
{
    WriteState state = {handle, 0};
    g_hash_table_foreach (dict, write_frame_list, & state);

    TAGDBG ("Total frame bytes written = %d.\n", state.written_size);
    return state.written_size;
}
Exemple #7
0
static gboolean read_frame (VFSFile * handle, gint max_size, gint version,
 gboolean syncsafe, gint * frame_size, gchar * key, guchar * * data, gint * size)
{
    ID3v2FrameHeader header;
    gint i;
    guint32 hdrsz = 0;

    if ((max_size -= sizeof (ID3v2FrameHeader)) < 0)
        return FALSE;

    if (vfs_fread (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof
     (ID3v2FrameHeader))
        return FALSE;

    if (! header.key[0]) /* padding */
        return FALSE;

    for (i = 0; i < 3; i++)
    {
        hdrsz |= (guint32) header.size[i] << ((2 - i) * 8);
        TAGDBG("header.size[%d] = %d hdrsz %d slot %d\n", i, header.size[i], hdrsz, 2 - i);
    }

//    hdrsz = GUINT32_TO_BE(hdrsz);
    if (hdrsz > max_size || hdrsz == 0)
        return FALSE;

    TAGDBG ("Found frame:\n");
    TAGDBG (" key = %.3s\n", header.key);
    TAGDBG (" size = %d\n", (gint) hdrsz);

    * frame_size = sizeof (ID3v2FrameHeader) + hdrsz;
    sprintf (key, "%.3s", header.key);

    * size = hdrsz;
    * data = g_malloc (* size);

    if (vfs_fread (* data, 1, * size, handle) != * size)
        return FALSE;

    TAGDBG ("Data size = %d.\n", * size);
    return TRUE;
}
Exemple #8
0
static void associate_int (Tuple * tuple, gint field, const gchar *
 customfield, const guchar * data, gint size)
{
    gchar * text = decode_text_frame (data, size);

    if (text == NULL || atoi (text) < 1)
    {
        g_free (text);
        return;
    }

    if (customfield != NULL)
        TAGDBG ("Custom field %s = %s.\n", customfield, text);
    else
        TAGDBG ("Field %i = %s.\n", field, text);

    tuple_associate_int (tuple, field, customfield, atoi (text));
    g_free (text);
}
Exemple #9
0
static void remove_frame (gint id, mowgli_dictionary_t * dict)
{
    GenericFrame * frame = mowgli_dictionary_retrieve (dict, id3_frames[id]);
    if (frame == NULL)
        return;

    TAGDBG ("Deleting frame %s.\n", id3_frames[id]);
    mowgli_dictionary_delete (dict, id3_frames[id]);
    free_generic_frame (frame);
}
Exemple #10
0
static void associate_string (Tuple * tuple, int field, const char *
 customfield, const unsigned char * data, int size)
{
    char * text = decode_text_frame (data, size);

    if (text == NULL || ! text[0])
    {
        g_free (text);
        return;
    }

    if (customfield != NULL)
        TAGDBG ("Custom field %s = %s.\n", customfield, text);
    else
        TAGDBG ("Field %i = %s.\n", field, text);

    tuple_set_str (tuple, field, customfield, text);
    g_free (text);
}
Exemple #11
0
static void decode_private_info (Tuple * tuple, const unsigned char * data, int size)
{
    char * text = g_strndup ((const char *) data, size);

    if (!strncmp(text, "WM/", 3))
    {
        char *separator = strchr(text, 0);
        if (separator == NULL)
            goto DONE;

        char * value = separator + 1;
        if (!strncmp(text, "WM/MediaClassPrimaryID", 22))
        {
            if (!memcmp(value, PRIMARY_CLASS_MUSIC, 16))
                tuple_set_str (tuple, -1, "media-class", "Music");
            if (!memcmp(value, PRIMARY_CLASS_AUDIO, 16))
                tuple_set_str (tuple, -1, "media-class", "Audio (non-music)");
        } else if (!strncmp(text, "WM/MediaClassSecondaryID", 24))
        {
            if (!memcmp(value, SECONDARY_CLASS_AUDIOBOOK, 16))
                tuple_set_str (tuple, -1, "media-class", "Audio Book");
            if (!memcmp(value, SECONDARY_CLASS_SPOKENWORD, 16))
                tuple_set_str (tuple, -1, "media-class", "Spoken Word");
            if (!memcmp(value, SECONDARY_CLASS_NEWS, 16))
                tuple_set_str (tuple, -1, "media-class", "News");
            if (!memcmp(value, SECONDARY_CLASS_TALKSHOW, 16))
                tuple_set_str (tuple, -1, "media-class", "Talk Show");
            if (!memcmp(value, SECONDARY_CLASS_GAMES_CLIP, 16))
                tuple_set_str (tuple, -1, "media-class", "Game Audio (clip)");
            if (!memcmp(value, SECONDARY_CLASS_GAMES_SONG, 16))
                tuple_set_str (tuple, -1, "media-class", "Game Soundtrack");
        } else {
            TAGDBG("Unrecognised tag %s (Windows Media) ignored\n", text);
        }
    } else {
        TAGDBG("Unable to decode private data, skipping: %s\n", text);
    }

DONE:
    g_free (text);
}
Exemple #12
0
static bool_t read_frame (VFSFile * handle, int max_size, int version,
 bool_t syncsafe, int * frame_size, char * key, char * * data, int * size)
{
    ID3v2FrameHeader header;
    int skip = 0;

    if ((max_size -= sizeof (ID3v2FrameHeader)) < 0)
        return FALSE;

    if (vfs_fread (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof
     (ID3v2FrameHeader))
        return FALSE;

    if (! header.key[0]) /* padding */
        return FALSE;

    header.size = (version == 3) ? GUINT32_FROM_BE (header.size) : unsyncsafe32
     (GUINT32_FROM_BE (header.size));
    header.flags = GUINT16_FROM_BE (header.flags);

    if (header.size > max_size || header.size == 0)
        return FALSE;

    TAGDBG ("Found frame:\n");
    TAGDBG (" key = %.4s\n", header.key);
    TAGDBG (" size = %d\n", (int) header.size);
    TAGDBG (" flags = %x\n", (int) header.flags);

    * frame_size = sizeof (ID3v2FrameHeader) + header.size;
    g_strlcpy (key, header.key, 5);

    if (header.flags & (ID3_FRAME_COMPRESSED | ID3_FRAME_ENCRYPTED))
    {
        TAGDBG ("Hit compressed/encrypted frame %s.\n", key);
        return FALSE;
    }

    if (header.flags & ID3_FRAME_HAS_GROUP)
        skip ++;
    if (header.flags & ID3_FRAME_HAS_LENGTH)
        skip += 4;

    if ((skip > 0 && vfs_fseek (handle, skip, SEEK_CUR)) || skip >= header.size)
        return FALSE;

    * size = header.size - skip;
    * data = g_malloc (* size);

    if (vfs_fread (* data, 1, * size, handle) != * size)
        return FALSE;

    if (syncsafe || (header.flags & ID3_FRAME_SYNCSAFE))
        * size = unsyncsafe (* data, * size);

    TAGDBG ("Data size = %d.\n", * size);
    return TRUE;
}
Exemple #13
0
static void add_text_frame (int id, const char * text, GHashTable * dict)
{
    if (text == NULL)
    {
        remove_frame (id, dict);
        return;
    }

    TAGDBG ("Adding text frame %s = %s.\n", id3_frames[id], text);
    int length = strlen (text);

    GenericFrame * frame = add_generic_frame (id, length + 1, dict);
    frame->data[0] = 3; /* UTF-8 encoding */
    memcpy (frame->data + 1, text, length);
}
Exemple #14
0
static void decode_comment (Tuple * tuple, const guchar * data, gint size)
{
    gchar * lang, * type, * value;

    if (! decode_comment_frame (data, size, & lang, & type, & value))
        return;

    TAGDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value);

    if (! type[0]) /* blank type == actual comment */
        tuple_associate_string (tuple, FIELD_COMMENT, NULL, value);

    g_free (lang);
    g_free (type);
    g_free (value);
}
Exemple #15
0
static void add_comment_frame (const char * text, GHashTable * dict)
{
    if (text == NULL)
    {
        remove_frame (ID3_COMMENT, dict);
        return;
    }

    TAGDBG ("Adding comment frame = %s.\n", text);
    int length = strlen (text);
    GenericFrame * frame = add_generic_frame (ID3_COMMENT, length + 5, dict);

    frame->data[0] = 3; /* UTF-8 encoding */
    strcpy ((char *) frame->data + 1, "eng"); /* well, it *might* be English */
    memcpy (frame->data + 5, text, length);
}
Exemple #16
0
static bool_t skip_extended_header_4 (VFSFile * handle, int * _size)
{
    uint32_t size;

    if (vfs_fread (& size, 1, 4, handle) != 4)
        return FALSE;

    size = unsyncsafe32 (GUINT32_FROM_BE (size));

    TAGDBG ("Found v2.4 extended header, size = %d.\n", (int) size);

    if (vfs_fseek (handle, size - 4, SEEK_CUR))
        return FALSE;

    * _size = size;
    return TRUE;
}
Exemple #17
0
static gboolean skip_extended_header_3 (VFSFile * handle, gint * _size)
{
    guint32 size;

    if (vfs_fread (& size, 1, 4, handle) != 4)
        return FALSE;

    size = GUINT32_FROM_BE (size);

    TAGDBG ("Found v2.3 extended header, size = %d.\n", (gint) size);

    if (vfs_fseek (handle, size, SEEK_CUR))
        return FALSE;

    * _size = 4 + size;
    return TRUE;
}
Exemple #18
0
static void decode_txx (Tuple * tuple, const guchar * data, gint size)
{
    gchar * text = decode_text_frame (data, size);

    if (text == NULL)
        return;

    gchar *separator = strchr(text, 0);

    if (separator == NULL)
        return;

    gchar * value = separator + 1;
    TAGDBG ("TXX: %s = %s.\n", text, value);
    tuple_associate_string (tuple, -1, text, value);

    g_free (text);
}
Exemple #19
0
static gboolean parse_pic (const guchar * data, gint size, gchar * * mime,
 gint * type, void * * image_data, gint * image_size)
{
    const guchar * sep;
    const guchar * after;

    if (size < 2 || (sep = memchr (data + 1, 0, size - 2)) == NULL)
        return FALSE;

    after = sep + 2;
    * mime = g_strdup ((const gchar *) data + 1);
    * type = sep[1];
    * image_data = g_memdup (after, data + size - after);
    * image_size = data + size - after;

    TAGDBG ("PIC: mime = %s, type = %d, size = %d.\n", * mime,
     * type, * image_size);
    return TRUE;
}
Exemple #20
0
static gboolean parse_apic (const guchar * _data, gint size, gchar * * mime,
 gint * type, gchar * * desc, void * * image_data, gint * image_size)
{
    const gchar * data = (const gchar *) _data;
    const gchar * sep, * after;

    if (size < 2 || (sep = memchr (data + 1, 0, size - 2)) == NULL)
        return FALSE;

    if ((* desc = convert_text (sep + 2, data + size - sep - 2, data[0], TRUE,
     NULL, & after)) == NULL)
        return FALSE;

    * mime = g_strdup (data + 1);
    * type = sep[1];
    * image_data = g_memdup (after, data + size - after);
    * image_size = data + size - after;

    TAGDBG ("APIC: mime = %s, type = %d, desc = %s, size = %d.\n", * mime,
     * type, * desc, * image_size);
    return TRUE;
}
Exemple #21
0
static bool_t write_frame (VFSFile * handle, GenericFrame * frame, int *
 frame_size)
{
    TAGDBG ("Writing frame %s, size %d\n", frame->key, frame->size);

    ID3v2FrameHeader header;

    memcpy (header.key, frame->key, 4);
    header.size = syncsafe32 (frame->size);
    header.size = GUINT32_TO_BE (header.size);
    header.flags = 0;

    if (vfs_fwrite (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof
     (ID3v2FrameHeader))
        return FALSE;

    if (vfs_fwrite (frame->data, 1, frame->size, handle) != frame->size)
        return FALSE;

    * frame_size = sizeof (ID3v2FrameHeader) + frame->size;
    return TRUE;
}
Exemple #22
0
static bool_t validate_header (ID3v2Header * header, bool_t is_footer)
{
    if (memcmp (header->magic, is_footer ? "3DI" : "ID3", 3))
        return FALSE;

    if ((header->version != 3 && header->version != 4) || header->revision != 0)
        return FALSE;

    header->size = unsyncsafe32 (GUINT32_FROM_BE (header->size));

    TAGDBG ("Found ID3v2 %s:\n", is_footer ? "footer" : "header");
    TAGDBG (" magic = %.3s\n", header->magic);
    TAGDBG (" version = %d\n", (int) header->version);
    TAGDBG (" revision = %d\n", (int) header->revision);
    TAGDBG (" flags = %x\n", (int) header->flags);
    TAGDBG (" size = %d\n", (int) header->size);
    return TRUE;
}
Exemple #23
0
static gboolean validate_header (ID3v2Header * header)
{
    if (memcmp (header->magic, "ID3", 3))
        return FALSE;

    if ((header->version != 2))
        return FALSE;

    header->size = unsyncsafe32(GUINT32_FROM_BE(header->size));

    TAGDBG ("Found ID3v2 header:\n");
    TAGDBG (" magic = %.3s\n", header->magic);
    TAGDBG (" version = %d\n", (gint) header->version);
    TAGDBG (" revision = %d\n", (gint) header->revision);
    TAGDBG (" flags = %x\n", (gint) header->flags);
    TAGDBG (" size = %d\n", (gint) header->size);
    return TRUE;
}
Exemple #24
0
gboolean id3v22_read_tag (Tuple * tuple, VFSFile * handle)
{
    gint version, header_size, data_size;
    gboolean syncsafe;
    gsize offset;
    gint pos;

    if (! read_header (handle, & version, & syncsafe, & offset, & header_size,
     & data_size))
        return FALSE;

    TAGDBG("Reading tags from %i bytes of ID3 data in %s\n", data_size, handle->uri);

    for (pos = 0; pos < data_size; )
    {
        gint frame_size, size, id;
        gchar key[5];
        guchar * data;

        if (! read_frame (handle, data_size - pos, version, syncsafe,
         & frame_size, key, & data, & size))
	{
	    TAGDBG("read_frame failed at pos %i\n", pos);
            break;
	}

        id = get_frame_id (key);

        switch (id)
        {
          case ID3_ALBUM:
            associate_string (tuple, FIELD_ALBUM, NULL, data, size);
            break;
          case ID3_TITLE:
            associate_string (tuple, FIELD_TITLE, NULL, data, size);
            break;
          case ID3_COMPOSER:
            associate_string (tuple, FIELD_COMPOSER, NULL, data, size);
            break;
          case ID3_COPYRIGHT:
            associate_string (tuple, FIELD_COPYRIGHT, NULL, data, size);
            break;
          case ID3_DATE:
            associate_string (tuple, FIELD_DATE, NULL, data, size);
            break;
          case ID3_LENGTH:
            associate_int (tuple, FIELD_LENGTH, NULL, data, size);
            break;
          case ID3_FUCKO_ARTIST:
          case ID3_ARTIST:
            associate_string (tuple, FIELD_ARTIST, NULL, data, size);
            break;
          case ID3_TRACKNR:
            associate_int (tuple, FIELD_TRACK_NUMBER, NULL, data, size);
            break;
          case ID3_YEAR:
            associate_int (tuple, FIELD_YEAR, NULL, data, size);
            break;
          case ID3_GENRE:
            decode_genre (tuple, data, size);
            break;
          case ID3_COMMENT:
            decode_comment (tuple, data, size);
            break;
          case ID3_ENCODER:
            associate_string (tuple, -1, "encoder", data, size);
            break;
          case ID3_TXX:
            decode_txx (tuple, data, size);
            break;
          case ID3_RVA:
            decode_rva (tuple, data, size);
            break;
          default:
            TAGDBG ("Ignoring unsupported ID3 frame %s.\n", key);
            break;
        }

        g_free (data);
        pos += frame_size;
    }

    return TRUE;
}
Exemple #25
0
static gboolean id3v24_read_tag (Tuple * tuple, VFSFile * handle)
{
    gint version, header_size, data_size, footer_size;
    gboolean syncsafe;
    gint64 offset;
    gint pos;

    if (! read_header (handle, & version, & syncsafe, & offset, & header_size,
     & data_size, & footer_size))
        return FALSE;

    for (pos = 0; pos < data_size; )
    {
        gint frame_size, size, id;
        gchar key[5];
        guchar * data;

        if (! read_frame (handle, data_size - pos, version, syncsafe,
         & frame_size, key, & data, & size))
            break;

        id = get_frame_id (key);

        switch (id)
        {
          case ID3_ALBUM:
            associate_string (tuple, FIELD_ALBUM, NULL, data, size);
            break;
          case ID3_TITLE:
            associate_string (tuple, FIELD_TITLE, NULL, data, size);
            break;
          case ID3_COMPOSER:
            associate_string (tuple, FIELD_COMPOSER, NULL, data, size);
            break;
          case ID3_COPYRIGHT:
            associate_string (tuple, FIELD_COPYRIGHT, NULL, data, size);
            break;
          case ID3_DATE:
            associate_string (tuple, FIELD_DATE, NULL, data, size);
            break;
          case ID3_TIME:
            associate_int (tuple, FIELD_LENGTH, NULL, data, size);
            break;
          case ID3_LENGTH:
            associate_int (tuple, FIELD_LENGTH, NULL, data, size);
            break;
          case ID3_ARTIST:
            associate_string (tuple, FIELD_ARTIST, NULL, data, size);
            break;
          case ID3_TRACKNR:
            associate_int (tuple, FIELD_TRACK_NUMBER, NULL, data, size);
            break;
          case ID3_YEAR:
          case ID3_RECORDING_TIME:
            associate_int (tuple, FIELD_YEAR, NULL, data, size);
            break;
          case ID3_GENRE:
            decode_genre (tuple, data, size);
            break;
          case ID3_COMMENT:
            decode_comment (tuple, data, size);
            break;
          case ID3_PRIVATE:
            decode_private_info (tuple, data, size);
            break;
          case ID3_ENCODER:
            associate_string (tuple, -1, "encoder", data, size);
            break;
          case ID3_TXXX:
            decode_txxx (tuple, data, size);
            break;
          case ID3_RVA2:
            decode_rva2 (tuple, data, size);
            break;
          default:
            TAGDBG ("Ignoring unsupported ID3 frame %s.\n", key);
            break;
        }

        g_free (data);
        pos += frame_size;
    }

    return TRUE;
}
Exemple #26
0
static bool_t read_header (VFSFile * handle, int * version, bool_t *
 syncsafe, int64_t * offset, int * header_size, int * data_size, int *
 footer_size)
{
    ID3v2Header header, footer;

    if (vfs_fseek (handle, 0, SEEK_SET))
        return FALSE;

    if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof
     (ID3v2Header))
        return FALSE;

    if (validate_header (& header, FALSE))
    {
        * offset = 0;
        * version = header.version;
        * header_size = sizeof (ID3v2Header);
        * data_size = header.size;

        if (header.flags & ID3_HEADER_HAS_FOOTER)
        {
            if (vfs_fseek (handle, header.size, SEEK_CUR))
                return FALSE;

            if (vfs_fread (& footer, 1, sizeof (ID3v2Header), handle) != sizeof
             (ID3v2Header))
                return FALSE;

            if (! validate_header (& footer, TRUE))
                return FALSE;

            * footer_size = sizeof (ID3v2Header);
        }
        else
            * footer_size = 0;
    }
    else
    {
        int64_t end = vfs_fsize (handle);

        if (end < 0)
            return FALSE;

        if (vfs_fseek (handle, end - sizeof (ID3v2Header), SEEK_SET))
            return FALSE;

        if (vfs_fread (& footer, 1, sizeof (ID3v2Header), handle) != sizeof
         (ID3v2Header))
            return FALSE;

        if (! validate_header (& footer, TRUE))
            return FALSE;

        * offset = end - 2 * sizeof (ID3v2Header) - footer.size;
        * version = footer.version;
        * header_size = sizeof (ID3v2Header);
        * data_size = footer.size;
        * footer_size = sizeof (ID3v2Header);

        if (vfs_fseek (handle, * offset, SEEK_SET))
            return FALSE;

        if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof
         (ID3v2Header))
            return FALSE;

        if (! validate_header (& header, FALSE))
            return FALSE;
    }

    * syncsafe = (header.flags & ID3_HEADER_SYNCSAFE) ? TRUE : FALSE;

    if (header.flags & ID3_HEADER_HAS_EXTENDED_HEADER)
    {
        int extended_size = 0;

        if (header.version == 3)
        {
            if (! skip_extended_header_3 (handle, & extended_size))
                return FALSE;
        }
        else if (header.version == 4)
        {
            if (! skip_extended_header_4 (handle, & extended_size))
                return FALSE;
        }

        * header_size += extended_size;
        * data_size -= extended_size;
    }

    TAGDBG ("Offset = %d, header size = %d, data size = %d, footer size = "
     "%d.\n", (int) * offset, * header_size, * data_size, * footer_size);

    return TRUE;
}
Exemple #27
0
static bool_t id3v24_read_tag (Tuple * tuple, VFSFile * handle)
{
    int version, header_size, data_size, footer_size;
    bool_t syncsafe;
    int64_t offset;
    int pos;

    if (! read_header (handle, & version, & syncsafe, & offset, & header_size,
     & data_size, & footer_size))
        return FALSE;

    for (pos = 0; pos < data_size; )
    {
        int frame_size, size, id;
        char key[5];
        char * data;

        if (! read_frame (handle, data_size - pos, version, syncsafe,
         & frame_size, key, & data, & size))
            break;

        id = get_frame_id (key);

        switch (id)
        {
          case ID3_ALBUM:
            id3_associate_string (tuple, FIELD_ALBUM, data, size);
            break;
          case ID3_TITLE:
            id3_associate_string (tuple, FIELD_TITLE, data, size);
            break;
          case ID3_COMPOSER:
            id3_associate_string (tuple, FIELD_COMPOSER, data, size);
            break;
          case ID3_COPYRIGHT:
            id3_associate_string (tuple, FIELD_COPYRIGHT, data, size);
            break;
          case ID3_DATE:
            id3_associate_string (tuple, FIELD_DATE, data, size);
            break;
          case ID3_LENGTH:
            id3_associate_int (tuple, FIELD_LENGTH, data, size);
            break;
          case ID3_ARTIST:
            id3_associate_string (tuple, FIELD_ARTIST, data, size);
            break;
          case ID3_TRACKNR:
            id3_associate_int (tuple, FIELD_TRACK_NUMBER, data, size);
            break;
          case ID3_YEAR:
          case ID3_RECORDING_TIME:
            id3_associate_int (tuple, FIELD_YEAR, data, size);
            break;
          case ID3_GENRE:
            id3_decode_genre (tuple, data, size);
            break;
          case ID3_COMMENT:
            id3_decode_comment (tuple, data, size);
            break;
#if 0
          case ID3_PRIVATE:
            decode_private_info (tuple, data, size);
            break;
#endif
          case ID3_RVA2:
            id3_decode_rva (tuple, data, size);
            break;
          default:
            TAGDBG ("Ignoring unsupported ID3 frame %s.\n", key);
            break;
        }

        g_free (data);
        pos += frame_size;
    }

    return TRUE;
}
Exemple #28
0
gchar * convert_text (const gchar * text, gint length, gint encoding, gboolean
 nulled, gint * _converted, const gchar * * after)
{
    gchar * buffer = NULL;
    gsize converted = 0;

    TAGDBG ("length = %d, encoding = %d, nulled = %d\n", length, encoding,
     nulled);

    if (nulled)
    {
        const guchar null16[] = {0, 0};
        const gchar * null;

        switch (encoding)
        {
          case 0:
          case 3:
            if ((null = memchr (text, 0, length)) == NULL)
                return NULL;

            length = null - text;
            TAGDBG ("length before null = %d\n", length);

            if (after != NULL)
                * after = null + 1;

            break;
          case 1:
          case 2:
            if ((null = memfind (text, length, null16, 2)) == NULL)
                return NULL;

            length = null - text;
            TAGDBG ("length before null = %d\n", length);

            if (after != NULL)
                * after = null + 2;

            break;
        }
    }

    switch (encoding)
    {
      case 0:
      case 3:
        buffer = str_to_utf8_full (text, length, NULL, & converted, NULL);
        break;
      case 1:
        if (text[0] == (gchar) 0xff)
            buffer = g_convert (text + 2, length - 2, "UTF-8", "UTF-16LE", NULL,
             & converted, NULL);
        else
            buffer = g_convert (text + 2, length - 2, "UTF-8", "UTF-16BE", NULL,
             & converted, NULL);

        break;
      case 2:
        buffer = g_convert (text, length, "UTF-8", "UTF-16BE", NULL,
         & converted, NULL);
        break;
    }

    TAGDBG ("length converted: %d\n", (gint) converted);
    TAGDBG ("string: %s\n", buffer);

    if (_converted != NULL)
        * _converted = converted;

    return buffer;
}
Exemple #29
0
static void remove_frame (int id, GHashTable * dict)
{
    TAGDBG ("Deleting frame %s.\n", id3_frames[id]);
    g_hash_table_remove (dict, id3_frames[id]);
}