Skip to content

Commit

Permalink
General : Prevent setting a standard field twice using AdditionalFiel…
Browse files Browse the repository at this point in the history
…ds [#260]
  • Loading branch information
Zeugma440 committed Apr 17, 2024
1 parent 593b4fb commit 68c5f65
Show file tree
Hide file tree
Showing 17 changed files with 223 additions and 21 deletions.
2 changes: 1 addition & 1 deletion ATL.benchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static void Main(string[] args)

//browseFor(@"E:\Music\", "*.mp3");

//writeAt(@"D:\temp\wav\broadcastwave_bext_info.wav");
writeAt(@"D:\temp\m4a-mp4\261\321668598-26d5e109-ad7a-42ac-82fa-18c7134891f3.mp4");

//info(@"D:\temp\wav\74\empty_tagged_audacity.wav");

Expand Down
1 change: 1 addition & 0 deletions ATL.unit-test/IO/MetaData/APE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public APE()
emptyFile = "MP3/empty.mp3";
notEmptyFile = "MP3/APE.mp3";
tagType = MetaDataIOFactory.TagType.APE;
titleFieldCode = "TITLE";

// Initialize specific test data (Publisher and Description fields not supported in APE tag)
testData.Publisher = null;
Expand Down
1 change: 1 addition & 0 deletions ATL.unit-test/IO/MetaData/ID3v2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public ID3v2()
testData.OriginalReleaseDate = new DateTime(2003, 03, 23);

tagType = MetaDataIOFactory.TagType.ID3V2;
titleFieldCode = "TIT2";
var pics = testData.EmbeddedPictures;
foreach (PictureInfo pic in pics) pic.TagType = tagType;
testData.EmbeddedPictures = pics;
Expand Down
1 change: 1 addition & 0 deletions ATL.unit-test/IO/MetaData/MP4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public MP4()
emptyFile = "MP4/empty.m4a"; // Has empty udta/meta tags
notEmptyFile = "MP4/mp4.m4a";
tagType = MetaDataIOFactory.TagType.NATIVE;
titleFieldCode = "©nam";

// MP4 does not support leading zeroes
testData.TrackNumber = 1;
Expand Down
29 changes: 29 additions & 0 deletions ATL.unit-test/IO/MetaData/MetaIOTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public abstract class MetaIOTest
protected bool supportsExtraEmbeddedPictures = true;
protected bool supportsInternationalChars = true;
protected bool canMetaNotExist = true;
protected string titleFieldCode = "";

public delegate void StreamDelegate(FileStream fs);

Expand Down Expand Up @@ -567,6 +568,34 @@ protected void test_RW_UpdateTrackDiscZeroes(string fileName, bool useLeadingZer
Assert.AreEqual(testData.AdditionalFields.Count - 1, meta.AdditionalFields.Count);
}

// Setting a standard field using additional fields shouldn't be possible
if (testData.AdditionalFields != null && testData.AdditionalFields.Count > 0 && titleFieldCode.Length > 0)
{
theTag.Title = "THE TITLE";

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);

theTag.AdditionalFields = new Dictionary<string, string> { { titleFieldCode, "THAT TITLE" } };

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);
}


// Remove the tag and check that it has been indeed removed
Assert.IsTrue(theFile.RemoveTagFromFileAsync(tagType).GetAwaiter().GetResult());
Expand Down
29 changes: 28 additions & 1 deletion ATL.unit-test/IO/MetaData/PSF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public PSF()
{
emptyFile = "PSF/empty.psf";
notEmptyFile = "PSF/psf.psf";
titleFieldCode = "title";
tagType = MetaDataIOFactory.TagType.NATIVE;
}

[TestMethod]
Expand Down Expand Up @@ -97,8 +99,33 @@ public void TagIO_RW_PSF_Empty()
Assert.AreEqual("FPS", theFile.NativeTag.Genre);


// Setting a standard field using additional fields shouldn't be possible
theTag.Title = "THE TITLE";

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());
Assert.IsTrue(theFile.ReadFromFile());

var meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);

theTag.AdditionalFields = new Dictionary<string, string> { { titleFieldCode, "THAT TITLE" } };

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);


// Remove the tag and check that it has been indeed removed
Assert.IsTrue(theFile.RemoveTagFromFile(MetaDataIOFactory.TagType.NATIVE));
Assert.IsTrue(theFile.RemoveTagFromFile(tagType));

Assert.IsTrue(theFile.ReadFromFile());

Expand Down
27 changes: 27 additions & 0 deletions ATL.unit-test/IO/MetaData/VQF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public VQF()
{
emptyFile = "VQF/empty.vqf";
notEmptyFile = "VQF/vqf.vqf";
titleFieldCode = "NAME";
tagType = MetaDataIOFactory.TagType.NATIVE;
}

[TestMethod]
Expand Down Expand Up @@ -100,6 +102,31 @@ public void TagIO_RW_VQF_Empty()
Assert.AreEqual(22, theFile.NativeTag.TrackNumber);


// Setting a standard field using additional fields shouldn't be possible
theTag.Title = "THE TITLE";

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());
Assert.IsTrue(theFile.ReadFromFile());

var meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);

theTag.AdditionalFields = new Dictionary<string, string> { { titleFieldCode, "THAT TITLE" } };

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);


// Remove the tag and check that it has been indeed removed
Assert.IsTrue(theFile.RemoveTagFromFile(MetaDataIOFactory.TagType.NATIVE));

Expand Down
28 changes: 28 additions & 0 deletions ATL.unit-test/IO/MetaData/Vorbis_FLAC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public Vorbis_FLAC()
emptyFile = "FLAC/empty.flac";
notEmptyFile = "FLAC/flac.flac";
tagType = MetaDataIOFactory.TagType.NATIVE;
titleFieldCode = "TITLE";

var pics = testData.EmbeddedPictures;
foreach (PictureInfo pic in pics) pic.TagType = tagType;
testData.EmbeddedPictures = pics;
Expand Down Expand Up @@ -211,6 +213,32 @@ public void TagIO_RW_VorbisFLAC_Empty()
Assert.AreEqual(550, theFile.NativeTag.BPM);


// Setting a standard field using additional fields shouldn't be possible
theTag.Title = "THE TITLE";

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

var meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);

theTag.AdditionalFields = new Dictionary<string, string> { { titleFieldCode, "THAT TITLE" } };

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);


// Remove the tag and check that it has been indeed removed
Assert.IsTrue(theFile.RemoveTagFromFile(MetaDataIOFactory.TagType.NATIVE));

Expand Down
3 changes: 2 additions & 1 deletion ATL.unit-test/IO/MetaData/WAV.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public WAV()
tagType = MetaDataIOFactory.TagType.NATIVE;
supportsInternationalChars = false;
supportsExtraEmbeddedPictures = false;
titleFieldCode = "info.INAM";

testData.TrackTotal = 0;
}
Expand Down Expand Up @@ -420,7 +421,7 @@ public void TagIO_RW_WAV_BEXT_Empty()
}

[TestMethod]
public void TagIO_RW_WAV_INFO_Empty()
public void TagIO_RW_WAV_LIST_INFO_Empty()
{
initListInfoTestData();
test_RW_Empty(emptyFile, true, true, true, true);
Expand Down
27 changes: 27 additions & 0 deletions ATL.unit-test/IO/MetaData/WMA.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public WMA()
emptyFile = "WMA/empty_full.wma";
notEmptyFile = "WMA/wma.wma";
tagType = MetaDataIOFactory.TagType.NATIVE;
titleFieldCode = "WM/TITLE";

testData.Conductor = null;
testData.Date = DateTime.MinValue;
Expand Down Expand Up @@ -138,6 +139,32 @@ public void TagIO_RW_WMA_Empty()
Assert.AreEqual("https://anywhe.re", theFile.NativeTag.AudioSourceUrl);


// Setting a standard field using additional fields shouldn't be possible
theTag.Title = "THE TITLE";

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

var meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);

theTag.AdditionalFields = new Dictionary<string, string> { { titleFieldCode, "THAT TITLE" } };

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, tagType).GetAwaiter().GetResult());

Assert.IsTrue(theFile.ReadFromFile(false, true));

meta = theFile.getMeta(tagType);
Assert.IsNotNull(meta);
Assert.IsTrue(meta.Exists);

Assert.AreEqual("THE TITLE", meta.Title);


// Remove the tag and check that it has been indeed removed
Assert.IsTrue(theFile.RemoveTagFromFile(MetaDataIOFactory.TagType.NATIVE));

Expand Down
8 changes: 7 additions & 1 deletion ATL/AudioData/IO/APEtag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ private int write(TagData tag, BinaryWriter w)
private int writeFrames(TagData tag, BinaryWriter w)
{
int nbFrames = 0;
// Keep these in memory to prevent setting them twice using AdditionalFields
var writtenFieldCodes = new HashSet<string>();

// Picture fields (first before textual fields, since APE tag is located on the footer)
foreach (PictureInfo picInfo in tag.Pictures)
Expand Down Expand Up @@ -445,6 +447,7 @@ private int writeFrames(TagData tag, BinaryWriter w)
{
string value = formatBeforeWriting(frameType, tag, map);
writeTextFrame(w, s, value);
writtenFieldCodes.Add(s.ToUpper());
nbFrames++;
}
break;
Expand All @@ -455,7 +458,10 @@ private int writeFrames(TagData tag, BinaryWriter w)
// Other textual fields
foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
{
if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TagType.ANY) || fieldInfo.TagType.Equals(getImplementedTagType())) && !fieldInfo.MarkedForDeletion)
if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TagType.ANY) || fieldInfo.TagType.Equals(getImplementedTagType()))
&& !fieldInfo.MarkedForDeletion
&& !writtenFieldCodes.Contains(fieldInfo.NativeFieldCode.ToUpper())
)
{
writeTextFrame(w, fieldInfo.NativeFieldCode, FormatBeforeWriting(fieldInfo.Value));
nbFrames++;
Expand Down
14 changes: 7 additions & 7 deletions ATL/AudioData/IO/ID3v2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,12 +1209,6 @@ public bool Read(Stream source, long offset, ReadTagParams readTagParams)
return result;
}

// Writes tag info using ID3v2.4 conventions
internal int writeInternal(TagData tag, BinaryWriter w)
{
return write(tag, w);
}

/// <summary>
/// Writes the given tag into the given Writer using ID3v2.4 conventions
/// </summary>
Expand Down Expand Up @@ -1437,6 +1431,8 @@ private int writeFrames(TagData tag, BinaryWriter w, Encoding tagEncoding)

IDictionary<string, Field> mapping = frameMapping_v24;
if (3 == Settings.ID3v2_tagSubVersion) mapping = frameMapping_v23;
// Keep these in memory to prevent setting them twice using AdditionalFields
var writtenFieldCodes = new HashSet<string>();

foreach (Field frameType in map.Keys)
{
Expand All @@ -1448,6 +1444,7 @@ private int writeFrames(TagData tag, BinaryWriter w, Encoding tagEncoding)

string value = formatBeforeWriting(frameType, tag, map);
writeTextFrame(w, s, value, tagEncoding);
writtenFieldCodes.Add(s.ToUpper());
nbFrames++;
break;
}
Expand All @@ -1468,7 +1465,10 @@ private int writeFrames(TagData tag, BinaryWriter w, Encoding tagEncoding)
// Other textual fields
foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
{
if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TagType.ANY) || fieldInfo.TagType.Equals(getImplementedTagType())) && !fieldInfo.MarkedForDeletion)
if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TagType.ANY) || fieldInfo.TagType.Equals(getImplementedTagType()))
&& !fieldInfo.MarkedForDeletion
&& !writtenFieldCodes.Contains(fieldInfo.NativeFieldCode.ToUpper())
)
{
var fieldCode = fieldInfo.NativeFieldCode;
if (fieldCode.Equals(VorbisTag.VENDOR_METADATA_ID)) continue; // Specific mandatory field exclusive to VorbisComment
Expand Down
4 changes: 4 additions & 0 deletions ATL/AudioData/IO/MP4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,8 @@ private int writeMeta(TagData tag, BinaryWriter w)
private int writeFrames(TagData tag, BinaryWriter w)
{
int counter = 0;
// Keep these in memory to prevent setting them twice using AdditionalFields
var writtenFieldCodes = new HashSet<string>();

IDictionary<Field, string> map = tag.ToMap();

Expand All @@ -1843,6 +1845,7 @@ private int writeFrames(TagData tag, BinaryWriter w)
string value = formatBeforeWriting(frameType, tag, map);

writeTextFrame(w, s, value);
writtenFieldCodes.Add(s.ToUpper());
counter++;
}
break;
Expand All @@ -1858,6 +1861,7 @@ private int writeFrames(TagData tag, BinaryWriter w)
&& !fieldInfo.MarkedForDeletion
&& !fieldInfo.NativeFieldCode.StartsWith("uuid.")
&& !fieldInfo.NativeFieldCode.StartsWith("xmp.")
&& !writtenFieldCodes.Contains(fieldInfo.NativeFieldCode.ToUpper())
)
{
writeTextFrame(w, fieldInfo.NativeFieldCode, FormatBeforeWriting(fieldInfo.Value));
Expand Down
9 changes: 8 additions & 1 deletion ATL/AudioData/IO/PSF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ protected override int write(TagData tag, Stream s, string zone)
private int write(TagData tag, BinaryWriter w)
{
int result = 0;
// Keep these in memory to prevent setting them twice using AdditionalFields
var writtenFieldCodes = new HashSet<string>();

w.Write(Utils.Latin1Encoding.GetBytes(TAG_HEADER));

Expand All @@ -423,6 +425,7 @@ private int write(TagData tag, BinaryWriter w)
if (map[frameType].Length > 0) // No frame with empty value
{
writeTextFrame(w, s, map[frameType]);
writtenFieldCodes.Add(s.ToUpper());
result++;
}
break;
Expand All @@ -433,7 +436,11 @@ private int write(TagData tag, BinaryWriter w)
// Other textual fields
foreach (MetaFieldInfo fieldInfo in tag.AdditionalFields)
{
if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TagType.ANY) || fieldInfo.TagType.Equals(getImplementedTagType())) && !fieldInfo.MarkedForDeletion && !fieldInfo.NativeFieldCode.Equals("utf8")) // utf8 already written
if ((fieldInfo.TagType.Equals(MetaDataIOFactory.TagType.ANY) || fieldInfo.TagType.Equals(getImplementedTagType()))
&& !fieldInfo.MarkedForDeletion
&& !fieldInfo.NativeFieldCode.Equals("utf8") // utf8 already written
&& !writtenFieldCodes.Contains(fieldInfo.NativeFieldCode.ToUpper())
)
{
writeTextFrame(w, fieldInfo.NativeFieldCode, FormatBeforeWriting(fieldInfo.Value));
result++;
Expand Down

0 comments on commit 68c5f65

Please sign in to comment.