Skip to content

Commit 98bc68d

Browse files
committed
Implement complex properties for Matroska
1 parent 8d02484 commit 98bc68d

10 files changed

Lines changed: 336 additions & 17 deletions

taglib/matroska/matroskaattachedfile.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* http://www.mozilla.org/MPL/ *
1919
***************************************************************************/
2020

21-
#ifndef HAS_MATROSKAATTACHEDFILE_H
22-
#define HAS_MATROSKAATTACHEDFILE_H
21+
#ifndef TAGLIB_MATROSKAATTACHEDFILE_H
22+
#define TAGLIB_MATROSKAATTACHEDFILE_H
2323

2424
#include "taglib_export.h"
2525

taglib/matroska/matroskaattachments.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ const Matroska::Attachments::AttachedFileList &Matroska::Attachments::attachedFi
5353
return d->files;
5454
}
5555

56+
Matroska::Attachments::AttachedFileList &Matroska::Attachments::attachedFiles()
57+
{
58+
return d->files;
59+
}
60+
5661
bool Matroska::Attachments::render()
5762
{
5863
EBML::MkAttachments attachments;

taglib/matroska/matroskaattachments.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* http://www.mozilla.org/MPL/ *
1919
***************************************************************************/
2020

21-
#ifndef HAS_MATROSKAATTACHMENTS_H
22-
#define HAS_MATROSKAATTACHMENTS_H
21+
#ifndef TAGLIB_MATROSKAATTACHMENTS_H
22+
#define TAGLIB_MATROSKAATTACHMENTS_H
2323

2424
#include <memory>
2525
#include "taglib_export.h"
@@ -56,6 +56,7 @@ namespace TagLib {
5656

5757
// private Element implementation
5858
bool render() override;
59+
AttachedFileList &attachedFiles();
5960

6061
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
6162
std::unique_ptr<AttachmentsPrivate> d;

taglib/matroska/matroskacues.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* http://www.mozilla.org/MPL/ *
1919
***************************************************************************/
2020

21-
#ifndef HAS_MATROSKACUES_H
22-
#define HAS_MATROSKACUES_H
21+
#ifndef TAGLIB_MATROSKACUES_H
22+
#define TAGLIB_MATROSKACUES_H
2323
#ifndef DO_NOT_DOCUMENT
2424

2525
#include "tlist.h"

taglib/matroska/matroskaelement.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* http://www.mozilla.org/MPL/ *
1919
***************************************************************************/
2020

21-
#ifndef HAS_MATROSKAELEMENT_H
22-
#define HAS_MATROSKAELEMENT_H
21+
#ifndef TAGLIB_MATROSKAELEMENT_H
22+
#define TAGLIB_MATROSKAELEMENT_H
2323
#ifndef DO_NOT_DOCUMENT
2424

2525
#include <memory>

taglib/matroska/matroskafile.cpp

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "matroskafile.h"
2222
#include "matroskatag.h"
2323
#include "matroskaattachments.h"
24+
#include "matroskaattachedfile.h"
2425
#include "matroskaseekhead.h"
2526
#include "matroskasegment.h"
2627
#include "ebmlutils.h"
@@ -29,9 +30,9 @@
2930
#include "tlist.h"
3031
#include "tdebug.h"
3132
#include "tagutils.h"
33+
#include "tpropertymap.h"
3234

3335
#include <memory>
34-
#include <vector>
3536

3637
using namespace TagLib;
3738

@@ -110,6 +111,132 @@ Matroska::Tag *Matroska::File::tag(bool create) const
110111
return d->tag.get();
111112
}
112113

114+
PropertyMap Matroska::File::properties() const
115+
{
116+
return d->tag ? d->tag->properties() : PropertyMap();
117+
}
118+
119+
void Matroska::File::removeUnsupportedProperties(const StringList &properties)
120+
{
121+
if(d->tag) {
122+
d->tag->removeUnsupportedProperties(properties);
123+
}
124+
}
125+
126+
PropertyMap Matroska::File::setProperties(const PropertyMap &properties)
127+
{
128+
if(!d->tag) {
129+
d->tag = std::make_unique<Tag>();
130+
}
131+
return d->tag->setProperties(properties);
132+
}
133+
134+
namespace {
135+
136+
String keyForAttachedFile(const Matroska::AttachedFile *attachedFile)
137+
{
138+
if(!attachedFile) {
139+
return {};
140+
}
141+
if(attachedFile->mediaType().startsWith("image/")) {
142+
return "PICTURE";
143+
}
144+
if(!attachedFile->mediaType().isEmpty()) {
145+
return attachedFile->mediaType();
146+
}
147+
if(!attachedFile->fileName().isEmpty()) {
148+
return attachedFile->fileName();
149+
}
150+
return String::fromLongLong(attachedFile->uid());
151+
}
152+
153+
unsigned long long stringToULongLong(const String &str, bool *ok)
154+
{
155+
const wchar_t *beginPtr = str.toCWString();
156+
wchar_t *endPtr;
157+
errno = 0;
158+
const unsigned long long value = ::wcstoull(beginPtr, &endPtr, 10);
159+
if(ok) {
160+
*ok = errno == 0 && endPtr > beginPtr && *endPtr == L'\0';
161+
}
162+
return value;
163+
}
164+
165+
}
166+
167+
StringList Matroska::File::complexPropertyKeys() const
168+
{
169+
StringList keys = TagLib::File::complexPropertyKeys();
170+
if(d->attachments) {
171+
const auto &attachedFiles = d->attachments->attachedFileList();
172+
for(const auto &attachedFile : attachedFiles) {
173+
String key = keyForAttachedFile(attachedFile);
174+
if(!key.isEmpty() && !keys.contains(key)) {
175+
keys.append(key);
176+
}
177+
}
178+
}
179+
return keys;
180+
}
181+
182+
List<VariantMap> Matroska::File::complexProperties(const String &key) const
183+
{
184+
List<VariantMap> props = TagLib::File::complexProperties(key);
185+
if(d->attachments) {
186+
const auto &attachedFiles = d->attachments->attachedFileList();
187+
for(const auto &attachedFile : attachedFiles) {
188+
if(keyForAttachedFile(attachedFile) == key) {
189+
VariantMap property;
190+
property.insert("data", attachedFile->data());
191+
property.insert("mimeType", attachedFile->mediaType());
192+
property.insert("description", attachedFile->description());
193+
property.insert("fileName", attachedFile->fileName());
194+
property.insert("uid", attachedFile->uid());
195+
props.append(property);
196+
}
197+
}
198+
}
199+
return props;
200+
}
201+
202+
bool Matroska::File::setComplexProperties(const String &key, const List<VariantMap> &value)
203+
{
204+
if(TagLib::File::setComplexProperties(key, value)) {
205+
return true;
206+
}
207+
208+
attachments(true)->clear();
209+
for(const auto &property : value) {
210+
auto mimeType = property.value("mimeType").value<String>();
211+
auto data = property.value("data").value<ByteVector>();
212+
auto fileName = property.value("fileName").value<String>();
213+
auto uid = property.value("uid").value<unsigned long long>();
214+
bool ok;
215+
unsigned long long uidKey;
216+
if(key.upper() == "PICTURE" && !mimeType.startsWith("image/")) {
217+
mimeType = data.startsWith("\x89PNG\x0d\x0a\x1a\x0a")
218+
? "image/png" : "image/jpeg";
219+
}
220+
else if(mimeType.isEmpty() && key.find("/") != -1) {
221+
mimeType = key;
222+
}
223+
else if(fileName.isEmpty() && key.find(".") != -1) {
224+
fileName = key;
225+
}
226+
else if(!uid && ((uidKey = stringToULongLong(key, &ok))) && ok) {
227+
uid = uidKey;
228+
}
229+
auto attachedFile = new AttachedFile;
230+
attachedFile->setData(data);
231+
attachedFile->setMediaType(mimeType);
232+
attachedFile->setDescription(property.value("description").value<String>());
233+
attachedFile->setFileName(fileName);
234+
attachedFile->setUID(uid);
235+
d->attachments->addAttachedFile(attachedFile);
236+
}
237+
return true;
238+
}
239+
113240
Matroska::Attachments *Matroska::File::attachments(bool create) const
114241
{
115242
if(!d->attachments && create)

taglib/matroska/matroskafile.h

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* http://www.mozilla.org/MPL/ *
1919
***************************************************************************/
2020

21-
#ifndef HAS_MATROSKAFILE_H
22-
#define HAS_MATROSKAFILE_H
21+
#ifndef TAGLIB_MATROSKAFILE_H
22+
#define TAGLIB_MATROSKAFILE_H
2323

2424
#include "taglib_export.h"
2525
#include "tfile.h"
@@ -30,23 +30,118 @@ namespace TagLib::Matroska {
3030
class Properties;
3131
class Tag;
3232
class Attachments;
33+
34+
/*!
35+
* Implementation of TagLib::File for Matroska.
36+
*/
3337
class TAGLIB_EXPORT File : public TagLib::File
3438
{
3539
public:
40+
/*!
41+
* Constructs a Matroska file from \a file. If \a readProperties is \c true the
42+
* file's audio properties will also be read.
43+
*
44+
* The \a readStyle parameter is currently unused.
45+
*/
3646
explicit File(FileName file, bool readProperties = true,
3747
Properties::ReadStyle readStyle = Properties::Average);
48+
49+
/*!
50+
* Constructs a Matroska file from \a stream. If \a readProperties is \c true the
51+
* file's audio properties will also be read.
52+
*
53+
* The \a readStyle parameter is currently unused.
54+
*/
3855
explicit File(IOStream *stream, bool readProperties = true,
3956
Properties::ReadStyle readStyle = Properties::Average);
57+
58+
/*!
59+
* Destroys this instance of the File.
60+
*/
4061
~File() override;
62+
4163
File(const File &) = delete;
4264
File &operator=(const File &) = delete;
43-
AudioProperties *audioProperties() const override;
65+
66+
/*!
67+
* Returns a pointer to the tag of the file.
68+
*
69+
* It will create a tag if one does not exist and returns a valid pointer.
70+
*
71+
* \note The tag <b>is still</b> owned by the Matroska::File and should not
72+
* be deleted by the user. It will be deleted when the file (object) is
73+
* destroyed.
74+
*/
4475
TagLib::Tag *tag() const override;
45-
Attachments *attachments(bool create = false) const;
76+
77+
/*!
78+
* Returns a pointer to the Matroska tag of the file.
79+
*
80+
* If \a create is \c false this may return a null pointer if there is no tag.
81+
* If \a create is \c true it will create a tag if one does not exist and
82+
* returns a valid pointer.
83+
*
84+
* \note The tag <b>is still</b> owned by the Matroska::File and should not
85+
* be deleted by the user. It will be deleted when the file (object)
86+
* destroyed.
87+
*/
4688
Tag *tag(bool create) const;
89+
90+
/*!
91+
* Implements the reading part of the unified property interface.
92+
*/
93+
PropertyMap properties() const override;
94+
95+
void removeUnsupportedProperties(const StringList &properties) override;
96+
97+
/*!
98+
* Implements the writing part of the unified tag dictionary interface.
99+
*/
100+
PropertyMap setProperties(const PropertyMap &) override;
101+
102+
/*!
103+
* Returns the keys for attached files, "PICTURE" for images, the media
104+
* type, file name or UID for other attached files.
105+
* The names of the binary simple tags are included too.
106+
*/
107+
StringList complexPropertyKeys() const override;
108+
109+
/*!
110+
* Get the pictures stored in the attachments as complex properties
111+
* for \a key "PICTURE". Other attached files can be retrieved, by
112+
* media type, file name or UID.
113+
* The attached files are returned as maps with keys "data", "mimeType",
114+
* "description", "fileName, "uid".
115+
* Binary simple tags can be retrieved as maps with keys "data", "name",
116+
* "targetTypeValue", "language", "defaultLanguage".
117+
*/
118+
List<VariantMap> complexProperties(const String &key) const override;
119+
120+
/*!
121+
* Set attached files as complex properties \a value, e.g. pictures for
122+
* \a key "PICTURE" with the maps in \a value having keys "data", "mimeType",
123+
* "description", "fileName, "uid". For other attached files, the mime type,
124+
* file name or UID can be used as the \a key.
125+
* Maps with keys "name" (with the same value as \a key) and "data" are
126+
* stored as binary simple tags with additional keys "targetTypeValue",
127+
* "language", "defaultLanguage".
128+
*/
129+
bool setComplexProperties(const String &key, const List<VariantMap> &value) override;
130+
131+
/*!
132+
* Returns the Matroska::Properties for this file. If no audio properties
133+
* were read then this will return a null pointer.
134+
*/
135+
AudioProperties *audioProperties() const override;
136+
137+
/*!
138+
* Save the file.
139+
*
140+
* This returns \c true if the save was successful.
141+
*/
47142
bool save() override;
48-
//PropertyMap properties() const override { return PropertyMap(); }
49-
//void removeUnsupportedProperties(const StringList &properties) override { }
143+
144+
Attachments *attachments(bool create = false) const;
50145

51146
/*!
52147
* Returns whether or not the given \a stream can be opened as a Matroska

taglib/matroska/matroskasimpletag.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
* http://www.mozilla.org/MPL/ *
1919
***************************************************************************/
2020

21-
#ifndef HAS_MATROSKASIMPLETAG_H
22-
#define HAS_MATROSKASIMPLETAG_H
21+
#ifndef TAGLIB_MATROSKASIMPLETAG_H
22+
#define TAGLIB_MATROSKASIMPLETAG_H
2323

2424
#include <memory>
2525
#include "tag.h"

0 commit comments

Comments
 (0)