Skip to content

Commit 8e6f190

Browse files
committed
Attempt to use .torrent encoding when parsing the torrent info itself.
Fixes #19
1 parent 3beddc3 commit 8e6f190

File tree

3 files changed

+72
-21
lines changed

3 files changed

+72
-21
lines changed

BencodeNET/Objects/BString.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ public override string ToString()
186186
/// </returns>
187187
public string ToString(Encoding encoding)
188188
{
189+
encoding = encoding ?? _encoding;
189190
return encoding.GetString(Value.ToArray());
190191
}
191192
}

BencodeNET/Parsing/TorrentParser.cs

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,25 @@ protected Torrent CreateTorrent(BDictionary data)
5858

5959
var info = data.Get<BDictionary>(TorrentFields.Info);
6060

61+
var encoding = ParseEncoding(data.Get<BString>(TorrentFields.Encoding)) ?? BencodeParser.Encoding;
62+
6163
var torrent = new Torrent
6264
{
6365
IsPrivate = info.Get<BNumber>(TorrentInfoFields.Private) == 1,
6466
PieceSize = info.Get<BNumber>(TorrentInfoFields.PieceLength),
6567
Pieces = info.Get<BString>(TorrentInfoFields.Pieces)?.Value.ToArray() ?? new byte[0],
6668

67-
Comment = data.Get<BString>(TorrentFields.Comment)?.ToString(),
68-
CreatedBy = data.Get<BString>(TorrentFields.CreatedBy)?.ToString(),
69+
Comment = data.Get<BString>(TorrentFields.Comment)?.ToString(encoding),
70+
CreatedBy = data.Get<BString>(TorrentFields.CreatedBy)?.ToString(encoding),
6971
Encoding = ParseEncoding(data.Get<BString>(TorrentFields.Encoding)),
7072
CreationDate = data.Get<BNumber>(TorrentFields.CreationDate),
7173

72-
File = ParseSingleFileInfo(info),
73-
Files = ParseMultiFileInfo(info),
74+
File = ParseSingleFileInfo(info, encoding),
75+
Files = ParseMultiFileInfo(info, encoding),
7476

75-
Trackers = ParseTrackers(data),
77+
Trackers = ParseTrackers(data, encoding),
7678

77-
ExtraFields = ParseAnyExtraFields(data)
79+
ExtraFields = ParseAnyExtraFields(data, encoding)
7880
};
7981

8082
return torrent;
@@ -157,41 +159,43 @@ private static void EnsureFields(IEnumerable<string> requiredFields, IEnumerable
157159
/// Parses file info for single-file torrents.
158160
/// </summary>
159161
/// <param name="info">The 'info'-dictionary of a torrent.</param>
162+
/// <param name="encoding"></param>
160163
/// <returns>The file info.</returns>
161-
protected virtual SingleFileInfo ParseSingleFileInfo(BDictionary info)
164+
protected virtual SingleFileInfo ParseSingleFileInfo(BDictionary info, Encoding encoding)
162165
{
163166
if (!info.ContainsKey(TorrentInfoFields.Length))
164167
return null;
165168

166169
return new SingleFileInfo
167170
{
168-
FileName = info.Get<BString>(TorrentInfoFields.Name)?.ToString(),
171+
FileName = info.Get<BString>(TorrentInfoFields.Name)?.ToString(encoding),
169172
FileSize = info.Get<BNumber>(TorrentInfoFields.Length),
170-
Md5Sum = info.Get<BString>(TorrentInfoFields.Md5Sum)?.ToString()
173+
Md5Sum = info.Get<BString>(TorrentInfoFields.Md5Sum)?.ToString(encoding)
171174
};
172175
}
173176

174177
/// <summary>
175178
/// Parses file info for multi-file torrents.
176179
/// </summary>
177180
/// <param name="info">The 'info'-dictionary of a torrent.</param>
181+
/// <param name="encoding"></param>
178182
/// <returns>The file info.</returns>
179-
protected virtual MultiFileInfoList ParseMultiFileInfo(BDictionary info)
183+
protected virtual MultiFileInfoList ParseMultiFileInfo(BDictionary info, Encoding encoding)
180184
{
181185
if (!info.ContainsKey(TorrentInfoFields.Files))
182186
return null;
183187

184188
var list = new MultiFileInfoList
185189
{
186-
DirectoryName = info.Get<BString>(TorrentInfoFields.Name).ToString(),
190+
DirectoryName = info.Get<BString>(TorrentInfoFields.Name).ToString(encoding),
187191
};
188192

189193
var fileInfos = info.Get<BList>(TorrentInfoFields.Files).Cast<BDictionary>()
190194
.Select(x => new MultiFileInfo
191195
{
192196
FileSize = x.Get<BNumber>(TorrentFilesFields.Length),
193-
Path = x.Get<BList>(TorrentFilesFields.Path)?.AsStrings().ToList(),
194-
Md5Sum = x.Get<BString>(TorrentFilesFields.Md5Sum)?.ToString()
197+
Path = x.Get<BList>(TorrentFilesFields.Path)?.AsStrings(encoding).ToList(),
198+
Md5Sum = x.Get<BString>(TorrentFilesFields.Md5Sum)?.ToString(encoding)
195199
});
196200

197201
list.AddRange(fileInfos);
@@ -204,8 +208,9 @@ protected virtual MultiFileInfoList ParseMultiFileInfo(BDictionary info)
204208
/// that are not otherwise represented in a <see cref="Torrent"/>.
205209
/// </summary>
206210
/// <param name="root"></param>
211+
/// <param name="encoding"></param>
207212
/// <returns></returns>
208-
protected virtual BDictionary ParseAnyExtraFields(BDictionary root)
213+
protected virtual BDictionary ParseAnyExtraFields(BDictionary root, Encoding encoding)
209214
{
210215
var extraFields = ParseExtraRootFields(root);
211216

@@ -220,6 +225,8 @@ protected virtual BDictionary ParseAnyExtraFields(BDictionary root)
220225
extraFields.Add(TorrentFields.Info, extraInfoFields);
221226
}
222227

228+
FixEncoding(extraFields, encoding);
229+
223230
return extraFields;
224231
}
225232

@@ -249,19 +256,63 @@ private BDictionary ParseExtraInfoFields(BDictionary info)
249256
return extraFields;
250257
}
251258

259+
// TODO: Unit tests
260+
private void FixEncoding(IBObject bobject, Encoding encoding)
261+
{
262+
var dictionary = bobject as BDictionary;
263+
if (dictionary != null)
264+
{
265+
FixEncodingInDictionary(dictionary, encoding);
266+
}
267+
268+
var list = bobject as BList;
269+
if (list != null)
270+
{
271+
FixEncodingInList(list, encoding);
272+
}
273+
274+
var value = bobject as BString;
275+
if (value != null)
276+
{
277+
value.Encoding = encoding;
278+
}
279+
}
280+
281+
private void FixEncodingInList(BList list, Encoding encoding)
282+
{
283+
foreach (var item in list)
284+
{
285+
FixEncoding(item, encoding);
286+
}
287+
}
288+
289+
private void FixEncodingInDictionary(BDictionary data, Encoding encoding)
290+
{
291+
foreach (var field in data)
292+
{
293+
// TODO: Add unit tests for this
294+
var key = field.Key.ToString(encoding);
295+
var isUtf8Key = key.EndsWith("utf-8", StringComparison.OrdinalIgnoreCase);
296+
var fieldEncoding = isUtf8Key ? Encoding.UTF8 : encoding;
297+
298+
FixEncoding(field.Value, fieldEncoding);
299+
}
300+
}
301+
252302
/// <summary>
253303
/// Parses trackers (announce URLs) from a torrent.
254304
/// </summary>
255305
/// <param name="data">The torrent data to parse trackers from.</param>
306+
/// <param name="encoding"></param>
256307
/// <returns>A list of list of trackers (announce URLs).</returns>
257-
protected virtual IList<IList<string>> ParseTrackers(BDictionary data)
308+
protected virtual IList<IList<string>> ParseTrackers(BDictionary data, Encoding encoding)
258309
{
259310
var trackerList = new List<IList<string>>();
260311
var primary = new List<string>();
261312
trackerList.Add(primary);
262313

263314
// Get single 'announce' url and add it to the primary list if there is any
264-
var announce = data.Get<BString>(TorrentFields.Announce)?.ToString();
315+
var announce = data.Get<BString>(TorrentFields.Announce)?.ToString(encoding);
265316
if (!string.IsNullOrEmpty(announce))
266317
{
267318
primary.Add(announce);
@@ -272,13 +323,13 @@ protected virtual IList<IList<string>> ParseTrackers(BDictionary data)
272323
if (announceLists?.Any() == true)
273324
{
274325
// Add the first list to the primary list and remove duplicates
275-
primary.AddRange(announceLists.First().AsStrings());
326+
primary.AddRange(announceLists.First().AsStrings(encoding));
276327
trackerList[0] = primary.Distinct().ToList();
277328

278329
// Add the other lists to the lists of lists of announce urls
279330
trackerList.AddRange(
280331
announceLists.Skip(1)
281-
.Select(x => x.AsStrings().ToList()));
332+
.Select(x => x.AsStrings(encoding).ToList()));
282333
}
283334

284335
return trackerList;

BencodeNET/project.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
{
22
"$schema": "http://json.schemastore.org/project",
3-
"version": "2.2.0-*",
3+
"version": "2.2.1-*",
44
"title": "BencodeNET",
55
"authors": [ "Søren Kruse" ],
66
"description": "A library for encoding and decoding bencode (e.g. torrent files)",
77
"packOptions": {
8-
//"summary": "A library for encoding and decoding bencode (e.g. torrent files)",
9-
"releaseNotes": "Fixed Torrent.Pieces and added Torrent.PiecesAsHexString property.",
8+
"releaseNotes": "Now uses the encoding information of a .torrent when parsing the torrent data.",
109
"projectUrl": "https://github.com/Krusen/BencodeNET",
1110
"licenseUrl": "https://github.com/Krusen/BencodeNET/blob/master/LICENSE.md",
1211
"requireLicenseAcceptance": false,

0 commit comments

Comments
 (0)