Skip to content

Commit 90ab5d4

Browse files
committed
pass unsupported boxes verbatim without breaking them
1 parent da41dc3 commit 90ab5d4

3 files changed

Lines changed: 108 additions & 0 deletions

File tree

src/TaglibSharp/Mpeg4/BoxFactory.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ parent.Box is IsoSampleDescriptionBox &&
114114
return new IsoFreeSpaceBox (header, file, handler);
115115
else if (type == BoxType.Mean || type == BoxType.Name)
116116
return new AppleAdditionalInfoBox (header, file, handler);
117+
else if (type == BoxType.Chpl)
118+
return new OpaqueBox (header, file, handler);
117119

118120
// If we still don't have a tag, and we're inside an
119121
// ItemListBox, load the box as an AnnotationBox

src/TaglibSharp/Mpeg4/BoxTypes.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static class BoxType
4747
public static readonly ReadOnlyByteVector Cmt = AppleTag.FixId ("cmt");
4848
public static readonly ReadOnlyByteVector Cond = "cond";
4949
public static readonly ReadOnlyByteVector Covr = "covr";
50+
public static readonly ReadOnlyByteVector Chpl = "chpl";
5051
public static readonly ReadOnlyByteVector Co64 = "co64";
5152
public static readonly ReadOnlyByteVector Cpil = "cpil";
5253
public static readonly ReadOnlyByteVector Cprt = "cprt";
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// OpaqueBox.cs: Provides a box implementation that preserves its
3+
// on-disk bytes exactly, with no re-parsing or re-rendering.
4+
//
5+
// This is used for atoms like the Nero chapter box (chpl) whose
6+
// internal format has multiple versions. Re-rendering through the
7+
// normal Box pipeline can silently corrupt the data (e.g. version
8+
// and flags bytes). By capturing the complete atom bytes on read
9+
// and returning them verbatim on render, we guarantee a lossless
10+
// round-trip.
11+
//
12+
// Copyright (C) 2026
13+
//
14+
// This library is free software; you can redistribute it and/or modify
15+
// it under the terms of the GNU Lesser General Public License version
16+
// 2.1 as published by the Free Software Foundation.
17+
//
18+
// This library is distributed in the hope that it will be useful, but
19+
// WITHOUT ANY WARRANTY; without even the implied warranty of
20+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+
// Lesser General Public License for more details.
22+
//
23+
// You should have received a copy of the GNU Lesser General Public
24+
// License along with this library; if not, write to the Free Software
25+
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26+
// USA
27+
//
28+
29+
using System;
30+
31+
namespace TagLib.Mpeg4
32+
{
33+
/// <summary>
34+
/// This class extends <see cref="Box" /> to provide a box that
35+
/// stores and renders its original on-disk bytes verbatim.
36+
/// No header or data re-serialization is performed.
37+
/// </summary>
38+
public class OpaqueBox : Box
39+
{
40+
#region Private Fields
41+
42+
/// <summary>
43+
/// The complete on-disk atom bytes (header + data).
44+
/// </summary>
45+
readonly ByteVector raw_bytes;
46+
47+
#endregion
48+
49+
50+
51+
#region Constructors
52+
53+
/// <summary>
54+
/// Constructs and initializes a new instance of <see
55+
/// cref="OpaqueBox" /> by reading the complete atom from
56+
/// the file at the position described by the header.
57+
/// </summary>
58+
/// <param name="header">
59+
/// A <see cref="BoxHeader" /> object containing the header
60+
/// to use for the new instance.
61+
/// </param>
62+
/// <param name="file">
63+
/// A <see cref="TagLib.File" /> object to read the contents
64+
/// of the box from.
65+
/// </param>
66+
/// <param name="handler">
67+
/// A <see cref="IsoHandlerBox" /> object containing the
68+
/// handler that applies to the new instance.
69+
/// </param>
70+
/// <exception cref="ArgumentNullException">
71+
/// <paramref name="file" /> is <see langword="null" />.
72+
/// </exception>
73+
public OpaqueBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base (header, handler)
74+
{
75+
if (file == null)
76+
throw new ArgumentNullException (nameof (file));
77+
78+
file.Seek (header.Position);
79+
raw_bytes = file.ReadBlock ((int)header.TotalBoxSize);
80+
}
81+
82+
#endregion
83+
84+
85+
86+
#region Protected Methods
87+
88+
/// <summary>
89+
/// Renders the box by returning the original on-disk bytes.
90+
/// </summary>
91+
/// <param name="topData">
92+
/// Ignored. The original bytes are returned as-is.
93+
/// </param>
94+
/// <returns>
95+
/// A <see cref="ByteVector" /> containing the exact bytes
96+
/// that were on disk when the box was read.
97+
/// </returns>
98+
protected override ByteVector Render (ByteVector topData)
99+
{
100+
return raw_bytes;
101+
}
102+
103+
#endregion
104+
}
105+
}

0 commit comments

Comments
 (0)