void ID3V2::parse_frame() { FXuint frameid; FXint framesize; FXbool skip=false; if (version==2) frameid = DEFINE_FRAME_V2(buffer[p+0],buffer[p+1],buffer[p+2]); else frameid = DEFINE_FRAME(buffer[p+0],buffer[p+1],buffer[p+2],buffer[p+3]); switch(version){ case 0 : case 1 : case 2 : framesize = (buffer[p+3]<<16) | (buffer[p+4]<<8) | (buffer[p+5]); break; case 3 : framesize = ID3_INT32(buffer+p+4); break; case 4 : framesize = ID3_SYNCSAFE_INT32(buffer+p+4); break; default : FXASSERT(0); p=size; return; break; }; if (version==2) GM_DEBUG_PRINT("[id3v2] frame %c%c%c\n",buffer[p+0],buffer[p+1],buffer[p+2]); else GM_DEBUG_PRINT("[id3v2] frame %c%c%c%c\n",buffer[p+0],buffer[p+1],buffer[p+2],buffer[p+3]); if (version==2) { p+=6; } else { FXint extra=0; if (buffer[9]&FRAME_COMPRESSED) { extra+=4; skip=true; } if (buffer[9]&FRAME_ENCRYPTED) { extra+=1; skip=true; } if (buffer[9]&FRAME_GROUP) { extra+=1; } p+=10+extra; } if (!skip) { switch(frameid) { case TP1 : case TPE1 : case TAL : case TALB : case TT2 : case TIT2 : parse_text_frame(frameid,framesize); break; case RVA2 : parse_rva2_frame(framesize); break; case PRIV : parse_priv_frame(framesize); break; case COMM : parse_comment_frame(framesize); break; case 0 : p=size; return; break; default : break; }; } p+=framesize; }
gboolean id3demux_id3v2_parse_frame (ID3TagsWorking * work) { const gchar *tag_name; gboolean result = FALSE; gint i; guint8 *frame_data = work->hdr.frame_data; guint frame_data_size = work->cur_frame_size; gchar *tag_str = NULL; GArray *tag_fields = NULL; guint8 *uu_data = NULL; #ifdef HAVE_ZLIB guint8 *uncompressed_data = NULL; #endif /* Check that the frame id is valid */ for (i = 0; i < 5 && work->frame_id[i] != '\0'; i++) { if (!g_ascii_isalnum (work->frame_id[i])) { GST_DEBUG ("Encountered invalid frame_id"); return FALSE; } } /* Can't handle encrypted frames right now (in case we ever do, we'll have * to do the decryption after the un-unsynchronisation and decompression, * not here) */ if (work->frame_flags & ID3V2_FRAME_FORMAT_ENCRYPTION) { GST_WARNING ("Encrypted frames are not supported"); return FALSE; } tag_name = gst_tag_from_id3_tag (work->frame_id); if (tag_name == NULL && strncmp (work->frame_id, "RVA2", 4) != 0 && strncmp (work->frame_id, "TXXX", 4) != 0 && strncmp (work->frame_id, "TDAT", 4) != 0 && strncmp (work->frame_id, "UFID", 4) != 0) { return FALSE; } if (work->frame_flags & (ID3V2_FRAME_FORMAT_COMPRESSION | ID3V2_FRAME_FORMAT_DATA_LENGTH_INDICATOR)) { if (work->hdr.frame_data_size <= 4) return FALSE; if (ID3V2_VER_MAJOR (work->hdr.version) == 3) { work->parse_size = GST_READ_UINT32_BE (frame_data); } else { work->parse_size = read_synch_uint (frame_data, 4); } frame_data += 4; frame_data_size -= 4; GST_LOG ("Un-unsynced data size %d (of %d)", work->parse_size, frame_data_size); if (work->parse_size > frame_data_size) { GST_WARNING ("ID3v2 frame %s data has invalid size %d (>%d)", work->frame_id, work->parse_size, frame_data_size); return FALSE; } } /* in v2.3 the frame sizes are not syncsafe, so the entire tag had to be * unsynced. In v2.4 the frame sizes are syncsafe so it's just the frame * data that needs un-unsyncing, but not the frame headers. */ if (ID3V2_VER_MAJOR (work->hdr.version) == 4) { if ((work->hdr.flags & ID3V2_HDR_FLAG_UNSYNC) != 0 || ((work->frame_flags & ID3V2_FRAME_FORMAT_UNSYNCHRONISATION) != 0)) { GST_DEBUG ("Un-unsyncing frame %s", work->frame_id); uu_data = id3demux_ununsync_data (frame_data, &frame_data_size); frame_data = uu_data; GST_MEMDUMP ("ID3v2 frame (un-unsyced)", frame_data, frame_data_size); } } work->parse_size = frame_data_size; if (work->frame_flags & ID3V2_FRAME_FORMAT_COMPRESSION) { #ifdef HAVE_ZLIB uLongf destSize = work->parse_size; Bytef *dest, *src; uncompressed_data = g_malloc (work->parse_size); dest = (Bytef *) uncompressed_data; src = (Bytef *) frame_data; if (uncompress (dest, &destSize, src, frame_data_size) != Z_OK) { g_free (uncompressed_data); g_free (uu_data); return FALSE; } if (destSize != work->parse_size) { GST_WARNING ("Decompressing ID3v2 frame %s did not produce expected size %d bytes (got %lu)", tag_name, work->parse_size, destSize); g_free (uncompressed_data); g_free (uu_data); return FALSE; } work->parse_data = uncompressed_data; #else GST_WARNING ("Compressed ID3v2 tag frame could not be decompressed" " because gstid3demux was compiled without zlib support"); g_free (uu_data); return FALSE; #endif } else { work->parse_data = frame_data; } if (work->frame_id[0] == 'T') { if (strcmp (work->frame_id, "TDAT") == 0) { parse_obsolete_tdat_frame (work); result = TRUE; } else if (strcmp (work->frame_id, "TXXX") == 0) { /* Handle user text frame */ tag_str = parse_user_text_identification_frame (work, &tag_name); } else { /* Text identification frame */ tag_fields = parse_text_identification_frame (work); } } else if (work->frame_id[0] == 'W' && strcmp (work->frame_id, "WXXX") != 0) { /* URL link frame: ISO-8859-1 encoded, one frame per tag */ tag_str = parse_url_link_frame (work, &tag_name); } else if (!strcmp (work->frame_id, "COMM")) { /* Comment */ result = parse_comment_frame (work); } else if (!strcmp (work->frame_id, "APIC")) { /* Attached picture */ result = parse_picture_frame (work); } else if (!strcmp (work->frame_id, "RVA2")) { /* Relative volume */ result = parse_relative_volume_adjustment_two (work); } else if (!strcmp (work->frame_id, "UFID")) { /* Unique file identifier */ tag_str = parse_unique_file_identifier (work, &tag_name); } #ifdef HAVE_ZLIB if (work->frame_flags & ID3V2_FRAME_FORMAT_COMPRESSION) { g_free (uncompressed_data); uncompressed_data = NULL; work->parse_data = frame_data; } #endif if (tag_str != NULL) { /* g_print ("Tag %s value %s\n", tag_name, tag_str); */ result = id3v2_tag_to_taglist (work, tag_name, tag_str); g_free (tag_str); } if (tag_fields != NULL) { if (strcmp (work->frame_id, "TCON") == 0) { /* Genre strings need special treatment */ result |= id3v2_genre_fields_to_taglist (work, tag_name, tag_fields); } else { gint t; for (t = 0; t < tag_fields->len; t++) { tag_str = g_array_index (tag_fields, gchar *, t); if (tag_str != NULL && tag_str[0] != '\0') result |= id3v2_tag_to_taglist (work, tag_name, tag_str); } } free_tag_strings (tag_fields); } g_free (uu_data); return result; }