diff --git a/ATL.unit-test/IO/MetaData/MP4.cs b/ATL.unit-test/IO/MetaData/MP4.cs index 99a641b7..012bb32e 100644 --- a/ATL.unit-test/IO/MetaData/MP4.cs +++ b/ATL.unit-test/IO/MetaData/MP4.cs @@ -1190,6 +1190,7 @@ public void TagIO_RW_MP4_Multiple_Values() { new ConsoleLogger(); + // == 1st variant : repetition of the same metadata structure string testFileLocation = TestUtils.CopyAsTempTestFile("MP4/multiple_artists.m4a"); AudioDataManager theFile = new AudioDataManager(AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation)); @@ -1210,6 +1211,30 @@ public void TagIO_RW_MP4_Multiple_Values() // Check if separated values are still intact after rewriting Assert.AreEqual("ArtistA" + ATL.Settings.InternalValueSeparator + "ArtistB" + ATL.Settings.InternalValueSeparator + "Demo", theFile.NativeTag.Artist); + if (Settings.DeleteAfterSuccess) File.Delete(testFileLocation); + + + // == 2nd variant : repetition of the 'data' atom inside one single field + testFileLocation = TestUtils.CopyAsTempTestFile("MP4/multiple_artists2.m4a"); + theFile = new AudioDataManager(AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation)); + + // Read + Assert.IsTrue(theFile.ReadFromFile(false, true)); + Assert.IsNotNull(theFile.NativeTag); + Assert.IsTrue(theFile.NativeTag.Exists); + + Assert.AreEqual("ArtistA" + ATL.Settings.InternalValueSeparator + "ArtistB" + ATL.Settings.InternalValueSeparator + "Demo2", theFile.NativeTag.Artist); + + // Write + theTag = new TagHolder(); + theTag.Title = "blah"; + + Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, MetaDataIOFactory.TagType.NATIVE).GetAwaiter().GetResult()); + Assert.IsTrue(theFile.ReadFromFile(false, true)); + + // Check if separated values are still intact after rewriting + Assert.AreEqual("ArtistA" + ATL.Settings.InternalValueSeparator + "ArtistB" + ATL.Settings.InternalValueSeparator + "Demo2", theFile.NativeTag.Artist); + // Get rid of the working copy if (Settings.DeleteAfterSuccess) File.Delete(testFileLocation); } diff --git a/ATL.unit-test/Resources/MP4/multiple_artists2.m4a b/ATL.unit-test/Resources/MP4/multiple_artists2.m4a new file mode 100644 index 00000000..85f68d90 Binary files /dev/null and b/ATL.unit-test/Resources/MP4/multiple_artists2.m4a differ diff --git a/ATL/AudioData/IO/MP4.cs b/ATL/AudioData/IO/MP4.cs index 05d68732..7e616194 100644 --- a/ATL/AudioData/IO/MP4.cs +++ b/ATL/AudioData/IO/MP4.cs @@ -1449,7 +1449,31 @@ private void readTag(BinaryReader source, ReadTagParams readTagParams) if (1 == dataClass) // UTF-8 Text { - values.Add(Encoding.UTF8.GetString(source.ReadBytes((int)metadataSize - 16))); + uint strSize = metadataSize; + long lastLocation; + var currentData = new List(); + + do + { + int dataSize = Math.Max(0, (int)strSize - 16); + if (dataSize > 0) + { + strData = Encoding.UTF8.GetString(source.ReadBytes((int)strSize - 16)); + currentData.Add(strData); + } + + // Look for multiple values + lastLocation = source.BaseStream.Position; + strSize = navigateToAtom(source, "data"); + if (strSize > 0) + { + source.BaseStream.Seek(8, SeekOrigin.Current); + metadataSize += strSize; + } + } while (strSize > 0); + source.BaseStream.Seek(lastLocation, SeekOrigin.Begin); + strData = string.Join(Settings.InternalValueSeparator, currentData); + values.Add(strData); } else if (21 == dataClass) // int8-16-24-32 { @@ -2051,7 +2075,7 @@ private void writeTextFrame(BinaryWriter writer, string frameCode, string text) { string[] values = text.Split(Settings.InternalValueSeparator); var first = true; - // Handle multiple values + // Handle multiple values = repeat the 'data' atom foreach (string value in values) { if (0 == value.Length) continue; @@ -2059,15 +2083,10 @@ private void writeTextFrame(BinaryWriter writer, string frameCode, string text) else { finalFramePos = writer.BaseStream.Position; - writer.BaseStream.Seek(frameSizePos1, SeekOrigin.Begin); - writer.Write(StreamUtils.EncodeBEUInt32(Convert.ToUInt32(finalFramePos - frameSizePos1))); writer.BaseStream.Seek(frameSizePos2, SeekOrigin.Begin); writer.Write(StreamUtils.EncodeBEUInt32(Convert.ToUInt32(finalFramePos - frameSizePos2))); writer.BaseStream.Seek(finalFramePos, SeekOrigin.Begin); - frameSizePos1 = writer.BaseStream.Position; - writer.Write(0); // Frame size placeholder to be rewritten in a few lines - writer.Write(Utils.Latin1Encoding.GetBytes(frameCode)); frameSizePos2 = writer.BaseStream.Position; writer.Write(0); // Frame size placeholder to be rewritten in a few lines writer.Write(Utils.Latin1Encoding.GetBytes("data"));