@@ -296,6 +296,74 @@ public async Task HybridTorrentWithPadding ()
296296 Assert . IsTrue ( sha256 . AsSpan ( ) . SequenceEqual ( torrent . CreatePieceHashes ( ) . GetHash ( 1 ) . V2Hash . Span ) ) ;
297297 }
298298
299+ [ Test ]
300+ public void HybridTorrent_FinalFileHasUnexpectedPadding ( [ Values ( true , false ) ] bool hasFinalFilePadding )
301+ {
302+ // Test validating both variants of torrent can be loaded
303+ //
304+ // https://github.com/bittorrent/bittorrent.org/issues/160
305+ //
306+ var v1Files = new BEncodedList {
307+ new BEncodedDictionary {
308+ { "length" , ( BEncodedNumber ) 9 } ,
309+ { "path" , new BEncodedList { ( BEncodedString ) "file1.txt" } } ,
310+ } ,
311+ new BEncodedDictionary {
312+ { "attr" , ( BEncodedString ) "p" } ,
313+ { "length" , ( BEncodedNumber ) 32759 } ,
314+ { "path" , new BEncodedList { ( BEncodedString ) ".pad32759" } } ,
315+ } ,
316+
317+ new BEncodedDictionary {
318+ { "length" , ( BEncodedNumber ) 14 } ,
319+ { "path" , new BEncodedList { ( BEncodedString ) "file2.txt" } } ,
320+ }
321+ } ;
322+
323+ if ( hasFinalFilePadding )
324+ v1Files . Add ( new BEncodedDictionary {
325+ { "attr" , ( BEncodedString ) "p" } ,
326+ { "length" , ( BEncodedNumber ) 32754 } ,
327+ { "path" , new BEncodedList { ( BEncodedString ) ".pad32754" } } ,
328+ } ) ;
329+
330+ var v2Files = new BEncodedDictionary {
331+ { "file1.txt" , new BEncodedDictionary {
332+ { "" , new BEncodedDictionary {
333+ { "length" , ( BEncodedNumber ) 9 } ,
334+ { "pieces root" , ( BEncodedString ) Enumerable . Repeat < byte > ( 0 , 32 ) . ToArray ( ) }
335+ } }
336+ } } ,
337+
338+ { "file2.txt" , new BEncodedDictionary {
339+ { "" , new BEncodedDictionary {
340+ { "length" , ( BEncodedNumber ) 14 } ,
341+ { "pieces root" , ( BEncodedString ) Enumerable . Repeat < byte > ( 1 , 32 ) . ToArray ( ) }
342+ } }
343+ } } ,
344+ } ;
345+
346+ var infoDict = new BEncodedDictionary {
347+ { "files" , v1Files } ,
348+ { "file tree" , v2Files } ,
349+ { "meta version" , ( BEncodedNumber ) 2 } ,
350+ { "name" , ( BEncodedString ) "padding test" } ,
351+ { "piece length" , ( BEncodedNumber ) 32768 } ,
352+ { "pieces" , ( BEncodedString ) new byte [ 40 ] }
353+ } ;
354+
355+ var dict = new BEncodedDictionary {
356+ { "info" , infoDict }
357+ } ;
358+
359+ var torrent = Torrent . Load ( dict ) ;
360+ Assert . AreEqual ( 2 , torrent . Files . Count ) ;
361+ Assert . AreEqual ( 9 , torrent . Files [ 0 ] . Length ) ;
362+ Assert . AreEqual ( 32768 - 9 , torrent . Files [ 0 ] . Padding ) ;
363+ Assert . AreEqual ( 14 , torrent . Files [ 1 ] . Length ) ;
364+ Assert . AreEqual ( hasFinalFilePadding ? 32768 - 14 : 0 , torrent . Files [ 1 ] . Padding ) ;
365+ }
366+
299367 static BEncodedString SHA1SumZeros ( long length )
300368 {
301369 using var hasher = IncrementalHash . CreateHash ( HashAlgorithmName . SHA1 ) ;
0 commit comments