mirror of
https://github.com/taglib/taglib.git
synced 2025-05-27 21:20:26 -04:00
C bindings for complex properties like pictures (#953)
Provides a unified API for complex properties in the same way as the Properties API in the C bindings. Since constructing and traversing complex properties in C is a bit complicated, there are convenience functions for the most common use case of getting or setting a single picture. TAGLIB_COMPLEX_PROPERTY_PICTURE(props, data, size, "Written by TagLib", "image/jpeg", "Front Cover"); taglib_complex_property_set(file, "PICTURE", props); and TagLib_Complex_Property_Attribute*** properties = taglib_complex_property_get(file, "PICTURE"); TagLib_Complex_Property_Picture_Data picture; taglib_picture_from_complex_property(properties, &picture);
This commit is contained in:
parent
1d213b8b98
commit
a3ad2d0aaa
@ -23,11 +23,14 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include "tstringlist.h"
|
||||
#include "tbytevectorlist.h"
|
||||
#include "tfile.h"
|
||||
#include "tpropertymap.h"
|
||||
#include "fileref.h"
|
||||
@ -412,7 +415,320 @@ void taglib_property_free(char **props)
|
||||
|
||||
char **p = props;
|
||||
while(*p) {
|
||||
free(*p++);
|
||||
free(*p++);
|
||||
}
|
||||
free(props);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Complex Properties API
|
||||
******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
bool _taglib_complex_property_set(
|
||||
TagLib_File *file, const char *key,
|
||||
const TagLib_Complex_Property_Attribute **value, bool append)
|
||||
{
|
||||
if(file == NULL || key == NULL)
|
||||
return false;
|
||||
|
||||
auto tfile = reinterpret_cast<File *>(file);
|
||||
|
||||
if(value == NULL) {
|
||||
return tfile->setComplexProperties(key, {});
|
||||
}
|
||||
|
||||
VariantMap map;
|
||||
const TagLib_Complex_Property_Attribute** attrPtr = value;
|
||||
while(*attrPtr) {
|
||||
const TagLib_Complex_Property_Attribute *attr = *attrPtr;
|
||||
String attrKey(attr->key);
|
||||
TagLib_Variant_Type type = attr->value.type;
|
||||
switch(type) {
|
||||
case TagLib_Variant_Void:
|
||||
map.insert(attrKey, Variant());
|
||||
break;
|
||||
case TagLib_Variant_Bool:
|
||||
map.insert(attrKey, attr->value.value.boolValue != 0);
|
||||
break;
|
||||
case TagLib_Variant_Int:
|
||||
map.insert(attrKey, attr->value.value.intValue);
|
||||
break;
|
||||
case TagLib_Variant_UInt:
|
||||
map.insert(attrKey, attr->value.value.uIntValue);
|
||||
break;
|
||||
case TagLib_Variant_LongLong:
|
||||
map.insert(attrKey, attr->value.value.longLongValue);
|
||||
break;
|
||||
case TagLib_Variant_ULongLong:
|
||||
map.insert(attrKey, attr->value.value.uLongLongValue);
|
||||
break;
|
||||
case TagLib_Variant_Double:
|
||||
map.insert(attrKey, attr->value.value.doubleValue);
|
||||
break;
|
||||
case TagLib_Variant_String:
|
||||
map.insert(attrKey, attr->value.value.stringValue);
|
||||
break;
|
||||
case TagLib_Variant_StringList: {
|
||||
StringList strs;
|
||||
if(attr->value.value.stringListValue) {
|
||||
char **s = attr->value.value.stringListValue;;
|
||||
while(*s) {
|
||||
strs.append(*s++);
|
||||
}
|
||||
}
|
||||
map.insert(attrKey, strs);
|
||||
break;
|
||||
}
|
||||
case TagLib_Variant_ByteVector:
|
||||
map.insert(attrKey, ByteVector(attr->value.value.byteVectorValue,
|
||||
attr->value.size));
|
||||
break;
|
||||
}
|
||||
++attrPtr;
|
||||
}
|
||||
|
||||
return append ? tfile->setComplexProperties(key, tfile->complexProperties(key).append(map))
|
||||
: tfile->setComplexProperties(key, {map});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BOOL taglib_complex_property_set(
|
||||
TagLib_File *file, const char *key,
|
||||
const TagLib_Complex_Property_Attribute **value)
|
||||
{
|
||||
return _taglib_complex_property_set(file, key, value, false);
|
||||
}
|
||||
|
||||
BOOL taglib_complex_property_set_append(
|
||||
TagLib_File *file, const char *key,
|
||||
const TagLib_Complex_Property_Attribute **value)
|
||||
{
|
||||
return _taglib_complex_property_set(file, key, value, true);
|
||||
}
|
||||
|
||||
char** taglib_complex_property_keys(TagLib_File *file)
|
||||
{
|
||||
if(file == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const StringList strs = reinterpret_cast<const File *>(file)->complexPropertyKeys();
|
||||
if(strs.isEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto keys = static_cast<char **>(malloc(sizeof(char *) * (strs.size() + 1)));
|
||||
char **keyPtr = keys;
|
||||
|
||||
for(const auto &str : strs) {
|
||||
*keyPtr++ = stringToCharArray(str);
|
||||
}
|
||||
*keyPtr = NULL;
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
TagLib_Complex_Property_Attribute*** taglib_complex_property_get(
|
||||
TagLib_File *file, const char *key)
|
||||
{
|
||||
if(file == NULL || key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const auto variantMaps = reinterpret_cast<const File *>(file)->complexProperties(key);
|
||||
if(variantMaps.isEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TagLib_Complex_Property_Attribute ***props = static_cast<TagLib_Complex_Property_Attribute ***>(
|
||||
malloc(sizeof(TagLib_Complex_Property_Attribute **) * (variantMaps.size() + 1)));
|
||||
TagLib_Complex_Property_Attribute ***propPtr = props;
|
||||
|
||||
for(const auto &variantMap : variantMaps) {
|
||||
TagLib_Complex_Property_Attribute **attrs = static_cast<TagLib_Complex_Property_Attribute **>(
|
||||
malloc(sizeof(TagLib_Complex_Property_Attribute *) * (variantMap.size() + 1)));
|
||||
TagLib_Complex_Property_Attribute *attr = static_cast<TagLib_Complex_Property_Attribute *>(
|
||||
malloc(sizeof(TagLib_Complex_Property_Attribute) * variantMap.size()));
|
||||
TagLib_Complex_Property_Attribute **attrPtr = attrs;
|
||||
for (const auto &[k, v] : variantMap) {
|
||||
attr->key = stringToCharArray(k);
|
||||
attr->value.size = 0;
|
||||
switch(v.type()) {
|
||||
case Variant::Void:
|
||||
attr->value.type = TagLib_Variant_Void;
|
||||
attr->value.value.stringValue = NULL;
|
||||
break;
|
||||
case Variant::Bool:
|
||||
attr->value.type = TagLib_Variant_Bool;
|
||||
attr->value.value.boolValue = v.value<bool>();
|
||||
break;
|
||||
case Variant::Int:
|
||||
attr->value.type = TagLib_Variant_Int;
|
||||
attr->value.value.intValue = v.value<int>();
|
||||
break;
|
||||
case Variant::UInt:
|
||||
attr->value.type = TagLib_Variant_UInt;
|
||||
attr->value.value.uIntValue = v.value<unsigned int>();
|
||||
break;
|
||||
case Variant::LongLong:
|
||||
attr->value.type = TagLib_Variant_LongLong;
|
||||
attr->value.value.longLongValue = v.value<long long>();
|
||||
break;
|
||||
case Variant::ULongLong:
|
||||
attr->value.type = TagLib_Variant_ULongLong;
|
||||
attr->value.value.uLongLongValue = v.value<unsigned long long>();
|
||||
break;
|
||||
case Variant::Double:
|
||||
attr->value.type = TagLib_Variant_Double;
|
||||
attr->value.value.doubleValue = v.value<double>();
|
||||
break;
|
||||
case Variant::String: {
|
||||
attr->value.type = TagLib_Variant_String;
|
||||
auto str = v.value<String>();
|
||||
attr->value.value.stringValue = stringToCharArray(str);
|
||||
attr->value.size = str.size();
|
||||
break;
|
||||
}
|
||||
case Variant::StringList: {
|
||||
attr->value.type = TagLib_Variant_StringList;
|
||||
StringList strs = v.value<StringList>();
|
||||
auto strPtr = static_cast<char **>(malloc(sizeof(char *) * (strs.size() + 1)));
|
||||
attr->value.value.stringListValue = strPtr;
|
||||
attr->value.size = strs.size();
|
||||
for(const auto &str : strs) {
|
||||
*strPtr++ = stringToCharArray(str);
|
||||
}
|
||||
*strPtr = NULL;
|
||||
break;
|
||||
}
|
||||
case Variant::ByteVector: {
|
||||
attr->value.type = TagLib_Variant_ByteVector;
|
||||
const ByteVector data = v.value<ByteVector>();
|
||||
auto bytePtr = static_cast<char *>(malloc(data.size()));
|
||||
attr->value.value.byteVectorValue = bytePtr;
|
||||
attr->value.size = data.size();
|
||||
::memcpy(bytePtr, data.data(), data.size());
|
||||
break;
|
||||
}
|
||||
case Variant::ByteVectorList:
|
||||
case Variant::VariantList:
|
||||
case Variant::VariantMap: {
|
||||
attr->value.type = TagLib_Variant_String;
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
attr->value.value.stringValue = stringToCharArray(ss.str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
*attrPtr++ = attr++;
|
||||
}
|
||||
*attrPtr++ = NULL;
|
||||
*propPtr++ = attrs;
|
||||
}
|
||||
*propPtr = NULL;
|
||||
return props;
|
||||
}
|
||||
|
||||
void taglib_picture_from_complex_property(
|
||||
TagLib_Complex_Property_Attribute*** properties,
|
||||
TagLib_Complex_Property_Picture_Data *picture)
|
||||
{
|
||||
if(!properties || !picture) {
|
||||
return;
|
||||
}
|
||||
std::memset(picture, 0, sizeof(*picture));
|
||||
TagLib_Complex_Property_Attribute*** propPtr = properties;
|
||||
while(!picture->data && *propPtr) {
|
||||
TagLib_Complex_Property_Attribute** attrPtr = *propPtr;
|
||||
while(*attrPtr) {
|
||||
TagLib_Complex_Property_Attribute *attr = *attrPtr;
|
||||
TagLib_Variant_Type type = attr->value.type;
|
||||
switch(type) {
|
||||
case TagLib_Variant_String:
|
||||
if(strcmp("mimeType", attr->key) == 0) {
|
||||
picture->mimeType = attr->value.value.stringValue;
|
||||
}
|
||||
else if(strcmp("description", attr->key) == 0) {
|
||||
picture->description = attr->value.value.stringValue;
|
||||
}
|
||||
else if(strcmp("pictureType", attr->key) == 0) {
|
||||
picture->pictureType = attr->value.value.stringValue;
|
||||
}
|
||||
break;
|
||||
case TagLib_Variant_ByteVector:
|
||||
if(strcmp("data", attr->key) == 0) {
|
||||
picture->data = attr->value.value.byteVectorValue;
|
||||
picture->size = attr->value.size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++attrPtr;
|
||||
}
|
||||
++propPtr;
|
||||
}
|
||||
}
|
||||
|
||||
void taglib_complex_property_free_keys(char **keys)
|
||||
{
|
||||
if(keys == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
char **k = keys;
|
||||
while(*k) {
|
||||
free(*k++);
|
||||
}
|
||||
free(keys);
|
||||
}
|
||||
|
||||
void taglib_complex_property_free(
|
||||
TagLib_Complex_Property_Attribute ***props)
|
||||
{
|
||||
if(props == NULL) {
|
||||
return;
|
||||
}
|
||||
TagLib_Complex_Property_Attribute*** propPtr = props;
|
||||
while(*propPtr) {
|
||||
TagLib_Complex_Property_Attribute** attrPtr = *propPtr;
|
||||
while(*attrPtr) {
|
||||
TagLib_Complex_Property_Attribute *attr = *attrPtr;
|
||||
TagLib_Variant_Type type = attr->value.type;
|
||||
switch(type) {
|
||||
case TagLib_Variant_String:
|
||||
free(attr->value.value.stringValue);
|
||||
break;
|
||||
case TagLib_Variant_StringList:
|
||||
if(attr->value.value.stringListValue) {
|
||||
char **s = attr->value.value.stringListValue;
|
||||
while(*s) {
|
||||
free(*s++);
|
||||
}
|
||||
free(attr->value.value.stringListValue);
|
||||
}
|
||||
break;
|
||||
case TagLib_Variant_ByteVector:
|
||||
free(attr->value.value.byteVectorValue);
|
||||
break;
|
||||
case TagLib_Variant_Void:
|
||||
case TagLib_Variant_Bool:
|
||||
case TagLib_Variant_Int:
|
||||
case TagLib_Variant_UInt:
|
||||
case TagLib_Variant_LongLong:
|
||||
case TagLib_Variant_ULongLong:
|
||||
case TagLib_Variant_Double:
|
||||
break;
|
||||
}
|
||||
free(attr->key);
|
||||
++attrPtr;
|
||||
}
|
||||
free(**propPtr);
|
||||
free(*propPtr++);
|
||||
}
|
||||
free(props);
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ TAGLIB_C_EXPORT char** taglib_property_keys(TagLib_File *file);
|
||||
* Get value(s) of property \a prop.
|
||||
*
|
||||
* \return NULL terminated array of C-strings (char *), only NULL if empty.
|
||||
It must be freed by the client using taglib_property_free().
|
||||
* It must be freed by the client using taglib_property_free().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char** taglib_property_get(TagLib_File *file, const char *prop);
|
||||
|
||||
@ -329,6 +329,238 @@ TAGLIB_C_EXPORT char** taglib_property_get(TagLib_File *file, const char *prop);
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_property_free(char **props);
|
||||
|
||||
/******************************************************************************
|
||||
* Complex Properties API
|
||||
******************************************************************************/
|
||||
|
||||
/*!
|
||||
* Types which can be stored in a TagLib_Variant.
|
||||
*
|
||||
* \related TagLib::Variant::Type
|
||||
* These correspond to TagLib::Variant::Type, but ByteVectorList, VariantList,
|
||||
* VariantMap are not supported and will be returned as their string
|
||||
* representation.
|
||||
*/
|
||||
typedef enum {
|
||||
TagLib_Variant_Void,
|
||||
TagLib_Variant_Bool,
|
||||
TagLib_Variant_Int,
|
||||
TagLib_Variant_UInt,
|
||||
TagLib_Variant_LongLong,
|
||||
TagLib_Variant_ULongLong,
|
||||
TagLib_Variant_Double,
|
||||
TagLib_Variant_String,
|
||||
TagLib_Variant_StringList,
|
||||
TagLib_Variant_ByteVector
|
||||
} TagLib_Variant_Type;
|
||||
|
||||
/*!
|
||||
* Discriminated union used in complex property attributes.
|
||||
*
|
||||
* \e type must be set according to the \e value union used.
|
||||
* \e size is only required for TagLib_Variant_ByteVector and must contain
|
||||
* the number of bytes.
|
||||
*
|
||||
* \related TagLib::Variant.
|
||||
*/
|
||||
typedef struct {
|
||||
TagLib_Variant_Type type;
|
||||
unsigned int size;
|
||||
union {
|
||||
char *stringValue;
|
||||
char *byteVectorValue;
|
||||
char **stringListValue;
|
||||
BOOL boolValue;
|
||||
int intValue;
|
||||
unsigned int uIntValue;
|
||||
long long longLongValue;
|
||||
unsigned long long uLongLongValue;
|
||||
double doubleValue;
|
||||
} value;
|
||||
} TagLib_Variant;
|
||||
|
||||
/*!
|
||||
* Attribute of a complex property.
|
||||
* Complex properties consist of a NULL-terminated array of pointers to
|
||||
* this structure with \e key and \e value.
|
||||
*/
|
||||
typedef struct {
|
||||
char *key;
|
||||
TagLib_Variant value;
|
||||
} TagLib_Complex_Property_Attribute;
|
||||
|
||||
/*!
|
||||
* Picture data extracted from a complex property by the convenience function
|
||||
* taglib_picture_from_complex_property().
|
||||
*/
|
||||
typedef struct {
|
||||
char *mimeType;
|
||||
char *description;
|
||||
char *pictureType;
|
||||
char *data;
|
||||
unsigned int size;
|
||||
} TagLib_Complex_Property_Picture_Data;
|
||||
|
||||
/*!
|
||||
* Declare complex property attributes to set a picture.
|
||||
* Can be used to define a variable \a var which can be used with
|
||||
* taglib_complex_property_set() and a "PICTURE" key to set an
|
||||
* embedded picture with the picture data \a dat of size \a siz
|
||||
* and description \a desc, mime type \a mime and picture type
|
||||
* \a typ (size is unsigned int, the other input parameters char *).
|
||||
*/
|
||||
#define TAGLIB_COMPLEX_PROPERTY_PICTURE(var, dat, siz, desc, mime, typ) \
|
||||
const TagLib_Complex_Property_Attribute \
|
||||
var##Attrs[] = { \
|
||||
{ \
|
||||
(char *)"data", \
|
||||
{ \
|
||||
TagLib_Variant_ByteVector, \
|
||||
(siz), \
|
||||
{ \
|
||||
(char *)(dat) \
|
||||
} \
|
||||
} \
|
||||
}, \
|
||||
{ \
|
||||
(char *)"mimeType", \
|
||||
{ \
|
||||
TagLib_Variant_String, \
|
||||
0U, \
|
||||
{ \
|
||||
(char *)(mime) \
|
||||
} \
|
||||
} \
|
||||
}, \
|
||||
{ \
|
||||
(char *)"description", \
|
||||
{ \
|
||||
TagLib_Variant_String, \
|
||||
0U, \
|
||||
{ \
|
||||
(char *)(desc) \
|
||||
} \
|
||||
} \
|
||||
}, \
|
||||
{ \
|
||||
(char *)"pictureType", \
|
||||
{ \
|
||||
TagLib_Variant_String, \
|
||||
0U, \
|
||||
{ \
|
||||
(char *)(typ) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
const TagLib_Complex_Property_Attribute *var[] = { \
|
||||
&var##Attrs[0], &var##Attrs[1], &var##Attrs[2], \
|
||||
&var##Attrs[3], NULL \
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sets the complex property \a key with \a value. Use \a value = NULL to
|
||||
* remove the property, otherwise it will be replaced with the NULL
|
||||
* terminated array of attributes in \a value.
|
||||
*
|
||||
* A picture can be set with the TAGLIB_COMPLEX_PROPERTY_PICTURE macro:
|
||||
*
|
||||
* \code {.c}
|
||||
* TagLib_File *file = taglib_file_new("myfile.mp3");
|
||||
* FILE *fh = fopen("mypicture.jpg", "rb");
|
||||
* if(fh) {
|
||||
* fseek(fh, 0L, SEEK_END);
|
||||
* long size = ftell(fh);
|
||||
* fseek(fh, 0L, SEEK_SET);
|
||||
* char *data = (char *)malloc(size);
|
||||
* fread(data, size, 1, fh);
|
||||
* TAGLIB_COMPLEX_PROPERTY_PICTURE(props, data, size, "Written by TagLib",
|
||||
* "image/jpeg", "Front Cover");
|
||||
* taglib_complex_property_set(file, "PICTURE", props);
|
||||
* taglib_file_save(file);
|
||||
* free(data);
|
||||
* fclose(fh);
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
TAGLIB_C_EXPORT BOOL taglib_complex_property_set(
|
||||
TagLib_File *file, const char *key,
|
||||
const TagLib_Complex_Property_Attribute **value);
|
||||
|
||||
/*!
|
||||
* Appends \a value to the complex property \a key (sets it if non-existing).
|
||||
* Use \a value = NULL to remove all values associated with the \a key.
|
||||
*/
|
||||
TAGLIB_C_EXPORT BOOL taglib_complex_property_set_append(
|
||||
TagLib_File *file, const char *key,
|
||||
const TagLib_Complex_Property_Attribute **value);
|
||||
|
||||
/*!
|
||||
* Get the keys of the complex properties.
|
||||
*
|
||||
* \return NULL terminated array of C-strings (char *), only NULL if empty.
|
||||
* It must be freed by the client using taglib_complex_property_free_keys().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char** taglib_complex_property_keys(TagLib_File *file);
|
||||
|
||||
/*!
|
||||
* Get value(s) of complex property \a key.
|
||||
*
|
||||
* \return NULL terminated array of property values, which are themselves an
|
||||
* array of property attributes, only NULL if empty.
|
||||
* It must be freed by the client using taglib_complex_property_free().
|
||||
*/
|
||||
TAGLIB_C_EXPORT TagLib_Complex_Property_Attribute*** taglib_complex_property_get(
|
||||
TagLib_File *file, const char *key);
|
||||
|
||||
/*!
|
||||
* Extract the complex property values of a picture.
|
||||
*
|
||||
* This function can be used to get the data from a "PICTURE" complex property
|
||||
* without having to traverse the whole variant map. A picture can be
|
||||
* retrieved like this:
|
||||
*
|
||||
* \code {.c}
|
||||
* TagLib_File *file = taglib_file_new("myfile.mp3");
|
||||
* TagLib_Complex_Property_Attribute*** properties =
|
||||
* taglib_complex_property_get(file, "PICTURE");
|
||||
* TagLib_Complex_Property_Picture_Data picture;
|
||||
* taglib_picture_from_complex_property(properties, &picture);
|
||||
* // Do something with picture.mimeType, picture.description,
|
||||
* // picture.pictureType, picture.data, picture.size, e.g. extract it.
|
||||
* FILE *fh = fopen("mypicture.jpg", "wb");
|
||||
* if(fh) {
|
||||
* fwrite(picture.data, picture.size, 1, fh);
|
||||
* fclose(fh);
|
||||
* }
|
||||
* taglib_complex_property_free(properties);
|
||||
* \endcode
|
||||
*
|
||||
* Note that the data in \a picture contains pointers to data in \a properties,
|
||||
* i.e. it only lives as long as the properties, until they are freed with
|
||||
* taglib_complex_property_free().
|
||||
* If you want to access multiple pictures or additional properties of FLAC
|
||||
* pictures ("width", "height", "numColors", "colorDepth" int values), you
|
||||
* have to traverse the \a properties yourself.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_picture_from_complex_property(
|
||||
TagLib_Complex_Property_Attribute*** properties,
|
||||
TagLib_Complex_Property_Picture_Data *picture);
|
||||
|
||||
/*!
|
||||
* Frees the NULL terminated array \a keys (as returned by
|
||||
* taglib_complex_property_keys()) and the C-strings it contains.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_complex_property_free_keys(char **keys);
|
||||
|
||||
/*!
|
||||
* Frees the NULL terminated array \a props of property attribute arrays
|
||||
* (as returned by taglib_complex_property_get()) and the data such as
|
||||
* C-strings and byte vectors contained in these attributes.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_complex_property_free(
|
||||
TagLib_Complex_Property_Attribute ***props);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -40,6 +40,7 @@ int main(int argc, char *argv[])
|
||||
TagLib_Tag *tag;
|
||||
const TagLib_AudioProperties *properties;
|
||||
char **propertiesMap;
|
||||
char **complexKeys;
|
||||
|
||||
taglib_set_strings_unicode(1);
|
||||
|
||||
@ -54,6 +55,7 @@ int main(int argc, char *argv[])
|
||||
tag = taglib_file_tag(file);
|
||||
properties = taglib_file_audioproperties(file);
|
||||
propertiesMap = taglib_property_keys(file);
|
||||
complexKeys = taglib_complex_property_keys(file);
|
||||
|
||||
if(tag != NULL) {
|
||||
printf("-- TAG (basic) --\n");
|
||||
@ -91,6 +93,73 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if(complexKeys != NULL) {
|
||||
char **keyPtr = complexKeys;
|
||||
while(*keyPtr) {
|
||||
TagLib_Complex_Property_Attribute*** properties =
|
||||
taglib_complex_property_get(file, *keyPtr);
|
||||
printf("%s:\n", *keyPtr);
|
||||
if(properties != NULL) {
|
||||
TagLib_Complex_Property_Attribute*** propPtr = properties;
|
||||
while(*propPtr) {
|
||||
TagLib_Complex_Property_Attribute** attrPtr = *propPtr;
|
||||
while(*attrPtr) {
|
||||
TagLib_Complex_Property_Attribute *attr = *attrPtr;
|
||||
TagLib_Variant_Type type = attr->value.type;
|
||||
printf(" %-11s - ", attr->key);
|
||||
switch(type) {
|
||||
case TagLib_Variant_Void:
|
||||
printf("null\n");
|
||||
break;
|
||||
case TagLib_Variant_Bool:
|
||||
printf("%s\n", attr->value.value.boolValue ? "true" : "false");
|
||||
break;
|
||||
case TagLib_Variant_Int:
|
||||
printf("%d\n", attr->value.value.intValue);
|
||||
break;
|
||||
case TagLib_Variant_UInt:
|
||||
printf("%u\n", attr->value.value.uIntValue);
|
||||
break;
|
||||
case TagLib_Variant_LongLong:
|
||||
printf("%lld\n", attr->value.value.longLongValue);
|
||||
break;
|
||||
case TagLib_Variant_ULongLong:
|
||||
printf("%llu\n", attr->value.value.uLongLongValue);
|
||||
break;
|
||||
case TagLib_Variant_Double:
|
||||
printf("%f\n", attr->value.value.doubleValue);
|
||||
break;
|
||||
case TagLib_Variant_String:
|
||||
printf("%s\n", attr->value.value.stringValue);
|
||||
break;
|
||||
case TagLib_Variant_StringList:
|
||||
if(attr->value.value.stringListValue) {
|
||||
char **strs = attr->value.value.stringListValue;
|
||||
char **s = strs;
|
||||
while(*s) {
|
||||
if(s != strs) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%s", *s++);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
case TagLib_Variant_ByteVector:
|
||||
printf("(%u bytes)\n", attr->value.size);
|
||||
break;
|
||||
}
|
||||
++attrPtr;
|
||||
}
|
||||
++propPtr;
|
||||
}
|
||||
taglib_complex_property_free(properties);
|
||||
}
|
||||
++keyPtr;
|
||||
}
|
||||
taglib_complex_property_free_keys(complexKeys);
|
||||
}
|
||||
|
||||
if(properties != NULL) {
|
||||
seconds = taglib_audioproperties_length(properties) % 60;
|
||||
minutes = (taglib_audioproperties_length(properties) - seconds) / 60;
|
||||
|
Loading…
Reference in New Issue
Block a user