11using System ;
2- using System . Collections . Generic ;
3- using System . Globalization ;
42using System . IO ;
53using System . Text ;
64using BencodeNET . Exceptions ;
@@ -11,9 +9,9 @@ namespace BencodeNET
119{
1210 public static class Bencode
1311 {
14- private static Encoding _defaultEncoding = Encoding . UTF8 ;
12+ private const int Int64MaxDigits = 19 ;
1513
16- private static readonly NumberFormatInfo _invariantNumberFormat = CultureInfo . InvariantCulture . NumberFormat ;
14+ private static Encoding _defaultEncoding = Encoding . UTF8 ;
1715
1816 /// <summary>
1917 /// Gets or sets the default encoding used to convert strings to and from bytes
@@ -184,7 +182,7 @@ public static BString DecodeString(BencodeStream stream, Encoding encoding)
184182 }
185183
186184 long stringLength ;
187- if ( ! long . TryParse ( lengthString . ToString ( ) , NumberStyles . None , _invariantNumberFormat , out stringLength ) )
185+ if ( ! TryParseLongFast ( lengthString . ToString ( ) , out stringLength ) )
188186 {
189187 throw new BencodeDecodingException < BString > ( string . Format ( "Invalid length of string '{0}'" , lengthString ) , startPosition ) ;
190188 }
@@ -278,7 +276,7 @@ public static BNumber DecodeNumber(BencodeStream stream)
278276 throw new BencodeDecodingException < BNumber > ( "Missing end character 'e'." , stream . Position ) ;
279277
280278 long number ;
281- if ( ! long . TryParse ( digits . ToString ( ) , NumberStyles . AllowLeadingSign , _invariantNumberFormat , out number ) )
279+ if ( ! TryParseLongFast ( digits . ToString ( ) , out number ) )
282280 {
283281 throw new BencodeDecodingException < BNumber > (
284282 string . Format ( "The value '{0}' is invalid. Supported values range from {1:N0} to {2:N0}" ,
@@ -437,5 +435,67 @@ public static TorrentFile DecodeTorrentFile(BencodeStream stream, Encoding encod
437435 var bdictionary = DecodeDictionary ( stream , encoding ) ;
438436 return new TorrentFile ( bdictionary ) ;
439437 }
438+
439+ /// <summary>
440+ /// A faster implementation than <see cref="long.TryParse(string, out long)"/>
441+ /// because we skip some checks that are not needed.
442+ /// </summary>
443+ private static bool TryParseLongFast ( string value , out long result )
444+ {
445+ result = 0 ;
446+
447+ if ( value == null )
448+ return false ;
449+
450+ var length = value . Length ;
451+
452+ // Cannot parse empty string
453+ if ( length == 0 )
454+ return false ;
455+
456+ var startIndex = 0 ;
457+ var isNegative = false ;
458+
459+ // Check if negative and set startIndex accordingly
460+ if ( value [ 0 ] == '-' )
461+ {
462+ // Cannot parse just '-'
463+ if ( length == 1 )
464+ return false ;
465+
466+ isNegative = true ;
467+ startIndex = 1 ;
468+ }
469+
470+ // Cannot parse string longer than long.MaxValue
471+ if ( length - startIndex > Int64MaxDigits )
472+ return false ;
473+
474+ long parsedLong = 0 ;
475+ for ( var i = startIndex ; i < length ; i ++ )
476+ {
477+ var character = value [ i ] ;
478+ if ( ! character . IsDigit ( ) )
479+ return false ;
480+
481+ var digit = character - '0' ;
482+
483+ if ( isNegative )
484+ parsedLong = 10 * parsedLong - digit ;
485+ else
486+ parsedLong = 10 * parsedLong + digit ;
487+ }
488+
489+ // Negative - should be less than zero
490+ if ( isNegative && parsedLong >= 0 )
491+ return false ;
492+
493+ // Positive - should be equal to or greater than zero
494+ if ( ! isNegative && parsedLong < 0 )
495+ return false ;
496+
497+ result = parsedLong ;
498+ return true ;
499+ }
440500 }
441501}
0 commit comments