Skip to content

Commit 7a5a101

Browse files
committed
Set Matroska tags which are not in the property map using complex properties
Also all attached files can be accessed and modified using complex properties.
1 parent d47d28f commit 7a5a101

4 files changed

Lines changed: 149 additions & 53 deletions

File tree

taglib/matroska/matroskafile.cpp

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -138,25 +138,23 @@ namespace {
138138
if(attachedFile.mediaType().startsWith("image/")) {
139139
return "PICTURE";
140140
}
141-
if(!attachedFile.mediaType().isEmpty()) {
142-
return attachedFile.mediaType();
143-
}
144141
if(!attachedFile.fileName().isEmpty()) {
145142
return attachedFile.fileName();
146143
}
147-
return String::fromLongLong(attachedFile.uid());
144+
if(!attachedFile.mediaType().isEmpty()) {
145+
return attachedFile.mediaType();
146+
}
147+
return String::fromULongLong(attachedFile.uid());
148148
}
149149

150-
unsigned long long stringToULongLong(const String &str, bool *ok)
150+
bool keyMatchesAttachedFile(const String &key, const Matroska::AttachedFile &attachedFile)
151151
{
152-
const wchar_t *beginPtr = str.toCWString();
153-
wchar_t *endPtr;
154-
errno = 0;
155-
const unsigned long long value = ::wcstoull(beginPtr, &endPtr, 10);
156-
if(ok) {
157-
*ok = errno == 0 && endPtr > beginPtr && *endPtr == L'\0';
158-
}
159-
return value;
152+
return !key.isEmpty() && (
153+
(key == "PICTURE" && attachedFile.mediaType().startsWith("image/")) ||
154+
key == attachedFile.fileName() ||
155+
key == attachedFile.mediaType() ||
156+
key == String::fromULongLong(attachedFile.uid())
157+
);
160158
}
161159

162160
}
@@ -182,7 +180,7 @@ List<VariantMap> Matroska::File::complexProperties(const String &key) const
182180
if(d->attachments) {
183181
const auto &attachedFiles = d->attachments->attachedFileList();
184182
for(const auto &attachedFile : attachedFiles) {
185-
if(keyForAttachedFile(attachedFile) == key) {
183+
if(keyMatchesAttachedFile(key, attachedFile)) {
186184
VariantMap property;
187185
property.insert("data", attachedFile.data());
188186
property.insert("mimeType", attachedFile.mediaType());
@@ -202,8 +200,19 @@ bool Matroska::File::setComplexProperties(const String &key, const List<VariantM
202200
return true;
203201
}
204202

205-
attachments(true)->clear();
203+
List<AttachedFile> &files = attachments(true)->attachedFiles();
204+
for(auto it = files.begin(); it != files.end();) {
205+
if(keyMatchesAttachedFile(key, *it)) {
206+
it = files.erase(it);
207+
}
208+
else {
209+
++it;
210+
}
211+
}
212+
206213
for(const auto &property : value) {
214+
if(property.isEmpty())
215+
continue;
207216
auto mimeType = property.value("mimeType").value<String>();
208217
auto data = property.value("data").value<ByteVector>();
209218
auto fileName = property.value("fileName").value<String>();
@@ -220,16 +229,26 @@ bool Matroska::File::setComplexProperties(const String &key, const List<VariantM
220229
else if(fileName.isEmpty() && key.find(".") != -1) {
221230
fileName = key;
222231
}
223-
else if(!uid && ((uidKey = stringToULongLong(key, &ok))) && ok) {
232+
else if(!uid && ((uidKey = key.toULongLong(&ok))) && ok) {
224233
uid = uidKey;
225234
}
226-
AttachedFile attachedFile;
227-
attachedFile.setData(data);
228-
attachedFile.setMediaType(mimeType);
229-
attachedFile.setDescription(property.value("description").value<String>());
230-
attachedFile.setFileName(fileName);
231-
attachedFile.setUID(uid);
232-
d->attachments->addAttachedFile(attachedFile);
235+
if(fileName.isEmpty() && !mimeType.isEmpty()) {
236+
int slashPos = mimeType.rfind('/');
237+
String ext = mimeType.substr(slashPos + 1);
238+
if(ext == "jpeg") {
239+
ext = "jpg";
240+
}
241+
fileName = "attachment." + ext;
242+
}
243+
if(!mimeType.isEmpty() && !fileName.isEmpty()) {
244+
AttachedFile attachedFile;
245+
attachedFile.setData(data);
246+
attachedFile.setMediaType(mimeType);
247+
attachedFile.setDescription(property.value("description").value<String>());
248+
attachedFile.setFileName(fileName);
249+
attachedFile.setUID(uid);
250+
d->attachments->addAttachedFile(attachedFile);
251+
}
233252
}
234253
return true;
235254
}

taglib/matroska/matroskatag.cpp

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ namespace
333333
);
334334
if(it != simpleTagsTranslation.end())
335335
return { std::get<1>(*it), std::get<2>(*it), std::get<3>(*it) };
336-
if (!key.isEmpty() && !key.startsWith("_"))
336+
if (!key.isEmpty())
337337
return { key, Matroska::SimpleTag::TargetTypeValue::Track, false };
338338
return { String(), Matroska::SimpleTag::TargetTypeValue::None, false };
339339
}
@@ -352,8 +352,7 @@ namespace
352352
return it != simpleTagsTranslation.end()
353353
? String(std::get<0>(*it), String::UTF8)
354354
: (targetTypeValue == Matroska::SimpleTag::TargetTypeValue::Track ||
355-
targetTypeValue == Matroska::SimpleTag::TargetTypeValue::None) &&
356-
!name.startsWith("_")
355+
targetTypeValue == Matroska::SimpleTag::TargetTypeValue::None)
357356
? name
358357
: String();
359358
}
@@ -399,6 +398,21 @@ String Matroska::Tag::TagPrivate::getTag(const String &key) const
399398
return it != tags.end() ? it->toString() : String();
400399
}
401400

401+
PropertyMap Matroska::Tag::properties() const
402+
{
403+
PropertyMap properties;
404+
for(const auto &simpleTag : std::as_const(d->tags)) {
405+
if(simpleTag.type() == SimpleTag::StringType) {
406+
String key = translateTag(simpleTag.name(), simpleTag.targetTypeValue());
407+
if(!key.isEmpty())
408+
properties[key].append(simpleTag.toString());
409+
else
410+
properties.addUnsupportedData(simpleTag.name());
411+
}
412+
}
413+
return properties;
414+
}
415+
402416
PropertyMap Matroska::Tag::setProperties(const PropertyMap &propertyMap)
403417
{
404418
// Remove all simple tags which would be returned in properties()
@@ -442,7 +456,8 @@ StringList Matroska::Tag::complexPropertyKeys() const
442456
{
443457
StringList keys;
444458
for(const SimpleTag &t : std::as_const(d->tags)) {
445-
if(t.type() == SimpleTag::BinaryType) {
459+
if(t.type() != SimpleTag::StringType ||
460+
translateTag(t.name(), t.targetTypeValue()).isEmpty()) {
446461
keys.append(t.name());
447462
}
448463
}
@@ -454,9 +469,16 @@ List<VariantMap> Matroska::Tag::complexProperties(const String& key) const
454469
List<VariantMap> props;
455470
if(key.upper() != "PICTURE") { // Pictures are handled at the file level
456471
for(const SimpleTag &t : std::as_const(d->tags)) {
457-
if(t.type() == SimpleTag::BinaryType) {
472+
if(t.name() == key &&
473+
(t.type() != SimpleTag::StringType ||
474+
translateTag(t.name(), t.targetTypeValue()).isEmpty())) {
458475
VariantMap property;
459-
property.insert("data", t.toByteVector());
476+
if(t.type() != SimpleTag::StringType) {
477+
property.insert("data", t.toByteVector());
478+
}
479+
else {
480+
property.insert("value", t.toString());
481+
}
460482
property.insert("name", t.name());
461483
property.insert("targetTypeValue", t.targetTypeValue());
462484
property.insert("language", t.language());
@@ -476,36 +498,39 @@ bool Matroska::Tag::setComplexProperties(const String& key, const List<VariantMa
476498
}
477499
d->removeSimpleTags(
478500
[&key](const SimpleTag &t) {
479-
return t.name() == key && t.type() == SimpleTag::BinaryType;
501+
return t.name() == key &&
502+
(t.type() != SimpleTag::StringType ||
503+
translateTag(t.name(), t.targetTypeValue()).isEmpty());
480504
}
481505
);
482506
bool result = false;
483507
for(const auto &property : value) {
484-
if(property.value("name").value<String>() == key && property.contains("data")) {
485-
d->tags.append(SimpleTag(
486-
key,
487-
property.value("data").value<ByteVector>(),
488-
static_cast<SimpleTag::TargetTypeValue>(
489-
property.value("targetTypeValue", 0).value<int>()),
490-
property.value("language").value<String>(),
491-
property.value("defaultLanguage", true).value<bool>()));
508+
if(property.value("name").value<String>() == key &&
509+
(property.contains("data") || property.contains("value") )) {
510+
SimpleTag::TargetTypeValue targetTypeValue;
511+
Variant targetTypeValueVar = property.value("targetTypeValue", 0);
512+
switch(targetTypeValueVar.type()) {
513+
case Variant::UInt:
514+
targetTypeValue = static_cast<SimpleTag::TargetTypeValue>(targetTypeValueVar.value<unsigned int>());
515+
break;
516+
case Variant::LongLong:
517+
targetTypeValue = static_cast<SimpleTag::TargetTypeValue>(targetTypeValueVar.value<long long>());
518+
break;
519+
case Variant::ULongLong:
520+
targetTypeValue = static_cast<SimpleTag::TargetTypeValue>(targetTypeValueVar.value<unsigned long long>());
521+
break;
522+
default:
523+
targetTypeValue = static_cast<SimpleTag::TargetTypeValue>(targetTypeValueVar.value<int>());
524+
}
525+
auto language = property.value("language").value<String>();
526+
bool defaultLanguage = property.value("defaultLanguage", true).value<bool>();
527+
d->tags.append(property.contains("data")
528+
? SimpleTag(key, property.value("data").value<ByteVector>(),
529+
targetTypeValue, language, defaultLanguage)
530+
: SimpleTag(key, property.value("value").value<String>(),
531+
targetTypeValue, language, defaultLanguage));
492532
result = true;
493533
}
494534
}
495535
return result;
496536
}
497-
498-
PropertyMap Matroska::Tag::properties() const
499-
{
500-
PropertyMap properties;
501-
for(const auto &simpleTag : std::as_const(d->tags)) {
502-
if(simpleTag.type() == SimpleTag::StringType) {
503-
String key = translateTag(simpleTag.name(), simpleTag.targetTypeValue());
504-
if(!key.isEmpty())
505-
properties[key].append(simpleTag.toString());
506-
else
507-
properties.addUnsupportedData(simpleTag.name());
508-
}
509-
}
510-
return properties;
511-
}

taglib/toolkit/tstring.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,30 @@ int String::toInt(bool *ok) const
495495
return static_cast<int>(value);
496496
}
497497

498+
long long String::toLongLong(bool *ok, int base) const
499+
{
500+
const wchar_t *beginPtr = d->data.c_str();
501+
wchar_t *endPtr;
502+
errno = 0;
503+
const long long value = ::wcstoll(beginPtr, &endPtr, base);
504+
if(ok) {
505+
*ok = errno == 0 && endPtr > beginPtr && *endPtr == L'\0';
506+
}
507+
return value;
508+
}
509+
510+
unsigned long long String::toULongLong(bool *ok, int base) const
511+
{
512+
const wchar_t *beginPtr = d->data.c_str();
513+
wchar_t *endPtr;
514+
errno = 0;
515+
const unsigned long long value = ::wcstoull(beginPtr, &endPtr, base);
516+
if(ok) {
517+
*ok = errno == 0 && endPtr > beginPtr && *endPtr == L'\0';
518+
}
519+
return value;
520+
}
521+
498522
String String::stripWhiteSpace() const
499523
{
500524
static const wchar_t *WhiteSpaceChars = L"\t\n\f\r ";
@@ -527,6 +551,11 @@ String String::fromLongLong(long long n) // static
527551
return std::to_string(n);
528552
}
529553

554+
String String::fromULongLong(unsigned long long n) // static
555+
{
556+
return std::to_string(n);
557+
}
558+
530559
wchar_t &String::operator[](int i)
531560
{
532561
detach();

taglib/toolkit/tstring.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,24 @@ namespace TagLib {
359359
*/
360360
int toInt(bool *ok = nullptr) const;
361361

362+
/*!
363+
* Convert the string to an integer.
364+
*
365+
* If the conversion was successful, it sets the value of \a *ok to
366+
* \c true and returns the integer. Otherwise it sets \a *ok to \c false
367+
* and the result is undefined.
368+
*/
369+
long long toLongLong(bool *ok = nullptr, int base = 10) const;
370+
371+
/*!
372+
* Convert the string to an integer.
373+
*
374+
* If the conversion was successful, it sets the value of \a *ok to
375+
* \c true and returns the integer. Otherwise it sets \a *ok to \c false
376+
* and the result is undefined.
377+
*/
378+
unsigned long long toULongLong(bool *ok = nullptr, int base = 10) const;
379+
362380
/*!
363381
* Returns a string with the leading and trailing whitespace stripped.
364382
*/
@@ -384,6 +402,11 @@ namespace TagLib {
384402
*/
385403
static String fromLongLong(long long n);
386404

405+
/*!
406+
* Converts the base-10 integer \a n to a string.
407+
*/
408+
static String fromULongLong(unsigned long long n);
409+
387410
/*!
388411
* Returns a reference to the character at position \a i.
389412
*/

0 commit comments

Comments
 (0)