Skip to content

Commit 0244c30

Browse files
committed
Fixed: Corrupting OPUS files on write
1 parent a130c49 commit 0244c30

File tree

3 files changed

+41
-14
lines changed

3 files changed

+41
-14
lines changed

src/TaglibSharp.Tests/FileFormats/OpusFormatTest.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,28 @@ public void TestCorruptionResistance ()
6767
{
6868
StandardTests.TestCorruptionResistance (TestPath.Samples + "corrupt/a.opus");
6969
}
70+
71+
[Test]
72+
public void CheckInvariantStartPosition()
73+
{
74+
// There was a corruption bug in OPUS file writer, the root cause of which was
75+
// the Ogg Bitstream class requiring the first page of the media data to be read
76+
// in order to process the tags. Then on write this media page is incorrectly
77+
// replaced with a page with absoluteGranularPosition = 0, which is not allowed.
78+
//
79+
// The sample file has the media beginning in the third page. To test the fix
80+
// ensure that the InvariantStartPosition is the location of the third page.
81+
// Previously we read/wrote the third page and corrupted it, and InvariantStartPosition
82+
// was set to the start of the fourth page.
83+
//
84+
// In principle the comments packet can span multiple pages, so if the test file
85+
// is updated in future this may need adjusting.
86+
87+
var p1 = file.Find("OggS", 0);
88+
var p2 = file.Find("OggS", p1 + 1);
89+
var p3 = file.Find("OggS", p2 + 1);
90+
91+
Assert.AreEqual(p3, file.InvariantStartPosition);
92+
}
7093
}
7194
}

src/TaglibSharp/Ogg/Bitstream.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,6 @@ public bool ReadPage (Page page)
119119
ByteVector[] packets = page.Packets;
120120

121121
for (int i = 0; i < packets.Length; i++) {
122-
if ((page.Header.Flags &
123-
PageFlags.FirstPacketContinued) == 0 &&
124-
previous_packet != null) {
125-
if (ReadPacket (previous_packet))
126-
return true;
127-
previous_packet = null;
128-
}
129-
130122

131123
ByteVector packet = packets[i];
132124

@@ -142,9 +134,9 @@ public bool ReadPage (Page page)
142134

143135
previous_packet = null;
144136

145-
if (i == packets.Length - 1) {
137+
if (i == packets.Length - 1 && !page.Header.LastPacketComplete) {
146138
// If we're at the last packet of the
147-
// page, store it.
139+
// page and it's continued on the next page, store it.
148140
previous_packet = new ByteVector (packet);
149141
} else if (ReadPacket (packet)) {
150142
// Otherwise, we need to process it.

src/TaglibSharp/Ogg/PageHeader.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public PageHeader (uint streamSerialNumber, uint pageNumber, PageFlags flags)
115115
Size = 0;
116116
DataSize = 0;
117117
packet_sizes = new List<int> ();
118+
LastPacketComplete = false;
118119

119120
if (pageNumber == 0 && (flags & PageFlags.FirstPacketContinued) == 0)
120121
Flags |= PageFlags.FirstPageOfStream;
@@ -200,6 +201,8 @@ public PageHeader (File file, long position)
200201

201202
if (packet_size > 0)
202203
packet_sizes.Add (packet_size);
204+
205+
LastPacketComplete = page_segments[page_segment_count - 1] < 255;
203206
}
204207

205208
/// <summary>
@@ -230,6 +233,7 @@ public PageHeader (PageHeader original, uint offset, PageFlags flags)
230233
Size = original.Size;
231234
DataSize = original.DataSize;
232235
packet_sizes = new List<int> ();
236+
LastPacketComplete = false;
233237

234238
if (PageSequenceNumber == 0 && (flags & PageFlags.FirstPacketContinued) == 0)
235239
Flags |= PageFlags.FirstPageOfStream;
@@ -257,12 +261,20 @@ public int[] PacketSizes {
257261
}
258262

259263
/// <summary>
260-
/// Gets the flags for the page described by the current
261-
/// instance.
264+
/// Indicates whether the final packet is continued on the next page
262265
/// </summary>
263266
/// <value>
264-
/// A <see cref="PageFlags" /> value containing the page
265-
/// flags.
267+
/// true if the final packet is complete and not continued on the next page
268+
/// </value>
269+
public bool LastPacketComplete { get; private set; }
270+
271+
/// <summary>
272+
/// Gets the flags for the page described by the current
273+
/// instance.
274+
/// </summary>
275+
/// <value>
276+
/// A <see cref="PageFlags" /> value containing the page
277+
/// flags.
266278
/// </value>
267279
public PageFlags Flags { get; private set; }
268280

0 commit comments

Comments
 (0)