Skip to content

Commit ad7c504

Browse files
committed
Add UTF-8 file name/path properties
#47 +semver: minor
1 parent 7e803dd commit ad7c504

File tree

6 files changed

+71
-7
lines changed

6 files changed

+71
-7
lines changed

BencodeNET.Tests/Torrents/TorrentParserTests.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ public class TorrentParserTests
2424
public TorrentParserTests()
2525
{
2626
BencodeParser = Substitute.For<IBencodeParser>();
27-
BencodeParser.Parse<BDictionary>((BencodeReader) null).ReturnsForAnyArgs(x => ParsedData);
27+
BencodeParser.Parse<BDictionary>(null).ReturnsForAnyArgs(x => ParsedData);
2828

2929
ValidSingleFileTorrentData = new BDictionary
3030
{
3131
[TorrentFields.Info] = new BDictionary
3232
{
3333
[TorrentInfoFields.Name] = (BString) "",
34+
[TorrentInfoFields.NameUtf8] = (BString) "",
3435
[TorrentInfoFields.Pieces] = (BString) "",
3536
[TorrentInfoFields.PieceLength] = (BNumber) 0,
3637
[TorrentInfoFields.Length] = (BNumber) 0
@@ -42,6 +43,7 @@ public TorrentParserTests()
4243
[TorrentFields.Info] = new BDictionary
4344
{
4445
[TorrentInfoFields.Name] = (BString) "",
46+
[TorrentInfoFields.NameUtf8] = (BString) "",
4547
[TorrentInfoFields.Pieces] = (BString) "",
4648
[TorrentInfoFields.PieceLength] = (BNumber) 0,
4749
[TorrentInfoFields.Files] = new BList()
@@ -394,13 +396,14 @@ public void AnnounceAndAnnounceList_DoesNotContainDuplicatesInPrimaryList(string
394396

395397
[Theory]
396398
[AutoMockedData]
397-
public void SingleFileInfo_IsParsed(long length, string fileName, string md5Sum)
399+
public void SingleFileInfo_IsParsed(long length, string fileName, string fileNameUtf8, string md5Sum)
398400
{
399401
// Arrange
400402
ParsedData = ValidSingleFileTorrentData;
401403
var info = ParsedData.Get<BDictionary>(TorrentFields.Info);
402404
info[TorrentInfoFields.Length] = (BNumber) length;
403405
info[TorrentInfoFields.Name] = (BString) fileName;
406+
info[TorrentInfoFields.NameUtf8] = (BString) fileNameUtf8;
404407
info[TorrentInfoFields.Md5Sum] = (BString) md5Sum;
405408

406409
// Act
@@ -414,12 +417,34 @@ public void SingleFileInfo_IsParsed(long length, string fileName, string md5Sum)
414417
torrent.File.Should().NotBeNull();
415418
torrent.File.FileSize.Should().Be(length);
416419
torrent.File.FileName.Should().Be(fileName);
420+
torrent.File.FileNameUtf8.Should().Be(fileNameUtf8);
417421
torrent.File.Md5Sum.Should().Be(md5Sum);
418422
}
419423

424+
[Fact]
425+
public void SingleFileInfo_NameUtf8_IsParsedAsUtf8EncodingIndependentlyOfActualEncoding()
426+
{
427+
var encoding = "ISO-8859-1";
428+
var fileName = "øæå"; // Use characters with different byte values for UTF8 and ISO-8859-1
429+
430+
ParsedData = ValidSingleFileTorrentData;
431+
ParsedData[TorrentFields.Encoding] = (BString) encoding;
432+
var info = ParsedData.Get<BDictionary>(TorrentFields.Info);
433+
info[TorrentInfoFields.Name] = new BString(fileName, Encoding.GetEncoding(encoding));
434+
info[TorrentInfoFields.NameUtf8] = new BString(fileName, Encoding.UTF8);
435+
436+
// Act
437+
var parser = new TorrentParser(BencodeParser);
438+
var torrent = parser.Parse((BencodeReader)null);
439+
440+
// Assert
441+
torrent.File.FileName.Should().Be(fileName);
442+
torrent.File.FileNameUtf8.Should().Be(fileName);
443+
}
444+
420445
[Theory]
421446
[AutoMockedData]
422-
public void MultiFileInfo_IsParsed(string directoryName, long length1, IList<string> paths1, string md5Sum1, long length2, IList<string> paths2, string md5Sum2)
447+
public void MultiFileInfo_IsParsed(string directoryName, long length1, IList<string> paths1, IList<string> paths1Utf8, string md5Sum1, long length2, IList<string> paths2, IList<string> paths2Utf8, string md5Sum2)
423448
{
424449
// Arrange
425450
ParsedData = ValidMultiFileTorrentData;
@@ -431,12 +456,14 @@ public void MultiFileInfo_IsParsed(string directoryName, long length1, IList<str
431456
{
432457
[TorrentFilesFields.Length] = (BNumber) length1,
433458
[TorrentFilesFields.Path] = new BList(paths1),
459+
[TorrentFilesFields.PathUtf8] = new BList(paths1Utf8),
434460
[TorrentFilesFields.Md5Sum] = (BString) md5Sum1
435461
},
436462
new BDictionary
437463
{
438464
[TorrentFilesFields.Length] = (BNumber) length2,
439465
[TorrentFilesFields.Path] = new BList(paths2),
466+
[TorrentFilesFields.PathUtf8] = new BList(paths2Utf8),
440467
[TorrentFilesFields.Md5Sum] = (BString) md5Sum2
441468
}
442469
};
@@ -453,9 +480,11 @@ public void MultiFileInfo_IsParsed(string directoryName, long length1, IList<str
453480
torrent.Files.Should().HaveCount(2);
454481
torrent.Files[0].FileSize.Should().Be(length1);
455482
torrent.Files[0].Path.Should().BeEquivalentTo(paths1);
483+
torrent.Files[0].PathUtf8.Should().BeEquivalentTo(paths1Utf8);
456484
torrent.Files[0].Md5Sum.Should().Be(md5Sum1);
457485
torrent.Files[1].FileSize.Should().Be(length2);
458486
torrent.Files[1].Path.Should().BeEquivalentTo(paths2);
487+
torrent.Files[1].PathUtf8.Should().BeEquivalentTo(paths2Utf8);
459488
torrent.Files[1].Md5Sum.Should().Be(md5Sum2);
460489
}
461490

BencodeNET/Torrents/MultiFileInfo.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ public class MultiFileInfo
1616
/// <summary>
1717
/// The file name. It just returns the last part of <see cref="Path"/>.
1818
/// </summary>
19-
public string FileName => Path.LastOrDefault();
19+
public string FileName => Path?.LastOrDefault();
20+
21+
/// <summary>
22+
/// The UTF-8 encoded file name. It just returns the last part of <see cref="PathUtf8"/>.
23+
/// </summary>
24+
public string FileNameUtf8 => PathUtf8?.LastOrDefault();
2025

2126
/// <summary>
2227
/// The file size in bytes.
@@ -36,6 +41,11 @@ public class MultiFileInfo
3641
/// </summary>
3742
public IList<string> Path { get; set; } = new List<string>();
3843

44+
/// <summary>
45+
/// A list of UTF-8 encoded file path elements.
46+
/// </summary>
47+
public IList<string> PathUtf8 { get; set; } = new List<string>();
48+
3949
/// <summary>
4050
/// The full path of the file including file name.
4151
/// </summary>
@@ -44,5 +54,14 @@ public string FullPath
4454
get => string.Join(System.IO.Path.DirectorySeparatorChar.ToString(), Path);
4555
set => Path = value.Split(new[] { System.IO.Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
4656
}
57+
58+
/// <summary>
59+
/// The full UTF-8 encoded path of the file including file name.
60+
/// </summary>
61+
public string FullPathUtf8
62+
{
63+
get => string.Join(System.IO.Path.DirectorySeparatorChar.ToString(), PathUtf8);
64+
set => PathUtf8 = value.Split(new[] { System.IO.Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
65+
}
4766
}
4867
}

BencodeNET/Torrents/SingleFileInfo.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
/// </remarks>
99
public class SingleFileInfo
1010
{
11-
// Name
1211
/// <summary>
1312
/// The file name. This is purely advisory.
1413
/// </summary>
@@ -17,6 +16,14 @@ public class SingleFileInfo
1716
/// </remarks>
1817
public string FileName { get; set; }
1918

19+
/// <summary>
20+
/// The UTF-8 encoded file name. This is purely advisory.
21+
/// </summary>
22+
/// <remarks>
23+
/// Corresponds to the 'name.utf-8' field.
24+
/// </remarks>
25+
public string FileNameUtf8 { get; set; }
26+
2027
/// <summary>
2128
/// The file size in bytes.
2229
/// </summary>

BencodeNET/Torrents/TorrentFields.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public static class TorrentFields
3434
public static class TorrentInfoFields
3535
{
3636
public const string Name = "name";
37+
public const string NameUtf8 = "name.utf-8";
3738
public const string Private = "private";
3839
public const string PieceLength = "piece length";
3940
public const string Pieces = "pieces";
@@ -44,6 +45,7 @@ public static class TorrentInfoFields
4445
public static readonly BString[] Keys =
4546
{
4647
Name,
48+
NameUtf8,
4749
Private,
4850
PieceLength,
4951
Pieces,
@@ -60,12 +62,14 @@ public static class TorrentFilesFields
6062
{
6163
public const string Length = "length";
6264
public const string Path = "path";
65+
public const string PathUtf8 = "path.utf-8";
6366
public const string Md5Sum = "md5sum";
6467

6568
public static readonly BString[] Keys =
6669
{
6770
Length,
6871
Path,
72+
PathUtf8,
6973
Md5Sum
7074
};
7175
}

BencodeNET/Torrents/TorrentParser.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ protected void EnsureValidTorrentData(BDictionary data)
180180
}
181181
}
182182

183-
private static void EnsureFields(IEnumerable<string> requiredFields, BDictionary data, string message = null)
183+
private static void EnsureFields(IList<string> requiredFields, BDictionary data, string message = null)
184184
{
185185
message = message ?? "Torrent is missing required field.";
186186

@@ -190,7 +190,7 @@ private static void EnsureFields(IEnumerable<string> requiredFields, BDictionary
190190
}
191191
}
192192

193-
private static void EnsureFields(IEnumerable<string> requiredFields, IEnumerable<BDictionary> list, string message = null)
193+
private static void EnsureFields(IList<string> requiredFields, IEnumerable<BDictionary> list, string message = null)
194194
{
195195
message = message ?? "Torrent is missing required field.";
196196

@@ -217,6 +217,7 @@ protected virtual SingleFileInfo ParseSingleFileInfo(BDictionary info, Encoding
217217
return new SingleFileInfo
218218
{
219219
FileName = info.Get<BString>(TorrentInfoFields.Name)?.ToString(encoding),
220+
FileNameUtf8 = info.Get<BString>(TorrentInfoFields.NameUtf8)?.ToString(Encoding.UTF8),
220221
FileSize = info.Get<BNumber>(TorrentInfoFields.Length),
221222
Md5Sum = info.Get<BString>(TorrentInfoFields.Md5Sum)?.ToString(encoding)
222223
};
@@ -243,6 +244,7 @@ protected virtual MultiFileInfoList ParseMultiFileInfo(BDictionary info, Encodin
243244
{
244245
FileSize = x.Get<BNumber>(TorrentFilesFields.Length),
245246
Path = x.Get<BList>(TorrentFilesFields.Path)?.AsStrings(encoding).ToList(),
247+
PathUtf8 = x.Get<BList>(TorrentFilesFields.PathUtf8)?.AsStrings(Encoding.UTF8).ToList(),
246248
Md5Sum = x.Get<BString>(TorrentFilesFields.Md5Sum)?.ToString(encoding)
247249
});
248250

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Added `FileNameUtf8` and `PathUtf8` and `FullPathUtf8` properties to `SingleFileInfo`/`MultiFileInfo`
10+
- These properties reads from `name.utf-8` and `path.utf-8` fields.
811

912
## [3.0.1] - 2019-10-17
1013
### Fixed

0 commit comments

Comments
 (0)