Beispiel #1
0
guint
id3demux_calc_id3v2_tag_size (GstBuffer * buf)
{
  guint8 *data, flags;
  guint size;

  g_assert (buf != NULL);
  g_assert (GST_BUFFER_SIZE (buf) >= ID3V2_HDR_SIZE);

  data = GST_BUFFER_DATA (buf);

  /* Check for 'ID3' string at start of buffer */
  if (data[0] != 'I' || data[1] != 'D' || data[2] != '3') {
    GST_DEBUG ("No ID3v2 tag in data");
    return 0;
  }

  /* Read the flags */
  flags = data[5];

  /* Read the size from the header */
  size = read_synch_uint (data + 6, 4);
  if (size == 0)
    return ID3V2_HDR_SIZE;

  size += ID3V2_HDR_SIZE;

  /* Expand the read size to include a footer if there is one */
  if ((flags & ID3V2_HDR_FLAG_FOOTER))
    size += 10;

  GST_DEBUG ("ID3v2 tag, size: %u bytes", size);
  return size;
}
Beispiel #2
0
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;
}