@@ -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 ;
0 commit comments