@@ -46,7 +46,7 @@ public XmpProfile(XDocument document)
4646 /// <summary>
4747 /// Convert the content of this <see cref="XmpProfile"/> into an <see cref="XDocument"/>.
4848 /// </summary>
49- /// <returns>The <see cref="XDocument"/></returns>
49+ /// <returns>The <see cref="XDocument"/> instance, or <see langword="null"/> if no XMP data is present. </returns>
5050 public XDocument ? ToXDocument ( )
5151 {
5252 byte [ ] ? data = this . Data ;
@@ -74,19 +74,30 @@ public XmpProfile(XDocument document)
7474 /// <returns>The <see cref="T:Byte[]"/></returns>
7575 public byte [ ] ToByteArray ( )
7676 {
77- Guard . NotNull ( this . Data ) ;
78- byte [ ] result = new byte [ this . Data . Length ] ;
77+ byte [ ] ? data = this . Data ;
78+
79+ if ( data is null )
80+ {
81+ return [ ] ;
82+ }
83+
84+ byte [ ] result = new byte [ data . Length ] ;
7985 this . Data . AsSpan ( ) . CopyTo ( result ) ;
8086 return result ;
8187 }
8288
8389 /// <inheritdoc/>
8490 public XmpProfile DeepClone ( )
8591 {
86- Guard . NotNull ( this . Data ) ;
92+ byte [ ] ? data = this . Data ;
93+ if ( data is null )
94+ {
95+ // Preserve the semantics of an "empty" profile when cloning.
96+ return new XmpProfile ( ) ;
97+ }
8798
88- byte [ ] clone = new byte [ this . Data . Length ] ;
89- this . Data . AsSpan ( ) . CopyTo ( clone ) ;
99+ byte [ ] clone = new byte [ data . Length ] ;
100+ data . AsSpan ( ) . CopyTo ( clone ) ;
90101 return new XmpProfile ( clone ) ;
91102 }
92103
@@ -118,7 +129,14 @@ private static byte[] SerializeDocument(XDocument document)
118129 }
119130
120131 // Allocation-free fast path for the normal case.
132+
133+ // Check for UTF-8 BOM (0xEF,0xBB,0xBF)
121134 bool hasBom = data . Length >= 3 && data [ 0 ] == 0xEF && data [ 1 ] == 0xBB && data [ 2 ] == 0xBF ;
135+
136+ // XMP metadata is commonly stored in fixed-size container blocks (e.g. TIFF tag 700).
137+ // Producers often pad unused space so the packet can be updated in-place without
138+ // rewriting the file. In practice this padding is either NUL (0x00) from the container
139+ // or 0x0F used by Adobe XMP writers. Both are invalid XML and must be trimmed.
122140 bool hasTrailingPad = data [ ^ 1 ] is 0 or 0x0F ;
123141
124142 if ( ! hasBom && ! hasTrailingPad )
@@ -146,7 +164,7 @@ private static byte[] SerializeDocument(XDocument document)
146164 int length = end - start ;
147165 if ( length <= 0 )
148166 {
149- return [ ] ;
167+ return null ;
150168 }
151169
152170 byte [ ] normalized = new byte [ length ] ;
0 commit comments