static void gulong_gst_date_transform (const GValue *src, GValue *dest) { gulong day = g_value_get_ulong (src); GDate *date = g_date_new_julian (day); gst_value_set_date (dest, date); g_date_free (date); }
static GstTagList * ape_demux_parse_tags (const guint8 * data, gint size) { GstTagList *taglist = gst_tag_list_new (); GST_LOG ("Reading tags from chunk of size %u bytes", size); /* get rid of header/footer */ if (size >= 32 && memcmp (data, "APETAGEX", 8) == 0) { data += 32; size -= 32; } if (size > 32 && memcmp (data + size - 32, "APETAGEX", 8) == 0) { size -= 32; } /* read actual tags - at least 10 bytes for tag header */ while (size >= 10) { guint len, n = 8; gchar *tag, *val; const gchar *gst_tag; GType gst_tag_type; /* find tag type and size */ len = GST_READ_UINT32_LE (data); while (n < size && data[n] != 0x0) n++; if (n == size) break; g_assert (data[n] == 0x0); n++; if (size - n < len) break; /* If the tag is empty, skip to the next one */ if (len == 0) goto next_tag; /* read */ tag = g_strndup ((gchar *) data + 8, n - 9); val = g_strndup ((gchar *) data + n, len); GST_LOG ("tag [%s], val[%s]", tag, val); /* special-case 'media' tag, could be e.g. "CD 1/2" */ if (g_ascii_strcasecmp (tag, "media") == 0) { gchar *sp, *sp2; g_free (tag); tag = g_strdup ("discnumber"); /* get rid of the medium in front */ sp = strchr (val, ' '); while (sp != NULL && (sp2 = strchr (sp + 1, ' ')) != NULL) sp = sp2; if (sp) { g_memmove (val, sp + 1, strlen (sp + 1) + 1); } } if (ape_demux_get_gst_tag_from_tag (tag, &gst_tag, &gst_tag_type)) { GValue v = { 0, }; switch (gst_tag_type) { case G_TYPE_INT:{ gint v_int; if (sscanf (val, "%d", &v_int) == 1) { g_value_init (&v, G_TYPE_INT); g_value_set_int (&v, v_int); } break; } case G_TYPE_UINT:{ guint v_uint, count; if (strcmp (gst_tag, GST_TAG_TRACK_NUMBER) == 0) { gint dummy; if (sscanf (val, "%u", &v_uint) == 1 && v_uint > 0) { g_value_init (&v, G_TYPE_UINT); g_value_set_uint (&v, v_uint); } GST_LOG ("checking for track count: %s", val); /* might be 0/N or -1/N to specify that there is only a count */ if (sscanf (val, "%d/%u", &dummy, &count) == 2 && count > 0) { gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_TRACK_COUNT, count, NULL); } } else if (strcmp (gst_tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) { gint dummy; if (sscanf (val, "%u", &v_uint) == 1 && v_uint > 0) { g_value_init (&v, G_TYPE_UINT); g_value_set_uint (&v, v_uint); } GST_LOG ("checking for volume count: %s", val); /* might be 0/N or -1/N to specify that there is only a count */ if (sscanf (val, "%d/%u", &dummy, &count) == 2 && count > 0) { gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_ALBUM_VOLUME_COUNT, count, NULL); } } else if (sscanf (val, "%u", &v_uint) == 1) { g_value_init (&v, G_TYPE_UINT); g_value_set_uint (&v, v_uint); } break; } case G_TYPE_STRING:{ g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, val); break; } case G_TYPE_DOUBLE:{ gdouble v_double; gchar *endptr; /* floating point strings can be "4,123" or "4.123" depending on * the locale. We need to be able to parse and read either version * no matter what our current locale is */ g_strdelimit (val, ",", '.'); v_double = g_ascii_strtod (val, &endptr); if (endptr != val) { g_value_init (&v, G_TYPE_DOUBLE); g_value_set_double (&v, v_double); } break; } default:{ if (gst_tag_type == GST_TYPE_DATE) { gint v_int; if (sscanf (val, "%d", &v_int) == 1) { GDate *date = g_date_new_dmy (1, 1, v_int); g_value_init (&v, GST_TYPE_DATE); gst_value_set_date (&v, date); g_date_free (date); } } else { GST_WARNING ("Unhandled tag type '%s' for tag '%s'", g_type_name (gst_tag_type), gst_tag); } break; } } if (G_VALUE_TYPE (&v) != 0) { gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND, gst_tag, &v, NULL); g_value_unset (&v); } } GST_DEBUG ("Read tag %s: %s", tag, val); g_free (tag); g_free (val); /* move data pointer */ next_tag: size -= len + n; data += len + n; } GST_DEBUG ("Taglist: %" GST_PTR_FORMAT, taglist); return taglist; }