diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index a3c5ea794..ab43bd92b 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -10,7 +10,6 @@ namespace ImageProcessor.UnitTests.Extensions { - using System; using System.Collections.Generic; using ImageProcessor.Common.Extensions; using NUnit.Framework; @@ -21,74 +20,6 @@ namespace ImageProcessor.UnitTests.Extensions [TestFixture] public class StringExtensionsUnitTests { - /// - /// Tests the MD5 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] - [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] - [TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] - [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] - public void TestToMd5Fingerprint(string input, string expected) - { - string result = input.ToMD5Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - - /// - /// Tests the SHA-1 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] - [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] - [TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] - [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] - public void TestToSHA1Fingerprint(string input, string expected) - { - string result = input.ToSHA1Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - - /// - /// Tests the SHA-256 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "9dfe6f15d1ab73af898739394fd22fd72a03db01834582f24bb2e1c66c7aaeae")] - [TestCase("lorem ipsum dolor", "ed03353266c993ea9afb9900a3ca688ddec1656941b1ca15ee1650a022616dfa")] - [TestCase("LoReM IpSuM DoLoR", "55f6cb90ba5cd8eeb6f5f16f083ebcd48ea06c34cc5aed8e33246fc3153d3898")] - [TestCase("1234567890", "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646")] - public void TestToSHA256Fingerprint(string input, string expected) - { - string result = input.ToSHA256Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - - /// - /// Tests the SHA-512 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "40aa1b203c9d8ee150b21c3c7cda8261492e5420c5f2b9f7380700e094c303b48e62f319c1da0e32eb40d113c5f1749cc61aeb499167890ab82f2cc9bb706971")] - [TestCase("lorem ipsum dolor", "cd813e13d1d3919cdccc31c19d8f8b70bd25e9819f8770a011c8c7a6228536e6c9427b338cd732f2da3c0444dfebef838b745cdaf3fd5dcba8db24fc83a3f6ef")] - [TestCase("LoReM IpSuM DoLoR", "3e4704d31f838456c0a5f0892afd392fbc79649a029d017b8104ebd00e2816d94ab4629f731765bf655088b130c51f6f47ca2f8b047749dbd992cf45e89ff431")] - [TestCase("1234567890", "12b03226a6d8be9c6e8cd5e55dc6c7920caaa39df14aab92d5e3ea9340d1c8a4d3d0b8e4314f1f6ef131ba4bf1ceb9186ab87c801af0d5c95b1befb8cedae2b9")] - public void TestToSHA512Fingerprint(string input, string expected) - { - string result = input.ToSHA512Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - /// /// Tests the passing to an integer array /// @@ -148,46 +79,5 @@ namespace ImageProcessor.UnitTests.Extensions Assert.AreEqual(item.Value, result); } } - - /// - /// Tests if the value is a valid URI path name. I.E the path part of a uri. - /// - /// The value to test - /// Whether the value is correct - /// - /// The full RFC3986 does not seem to pass the test with the square brackets - /// ':' is failing for some reason in VS but not elsewhere. Could be a build issue. - /// - [Test] - [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] - [TestCase("-", true)] - [TestCase(".", true)] - [TestCase("_", true)] - [TestCase("~", true)] - [TestCase(":", true)] - [TestCase("/", true)] - [TestCase("?", true)] - [TestCase("#", false)] - [TestCase("[", false)] - [TestCase("]", false)] - [TestCase("@", true)] - [TestCase("!", true)] - [TestCase("$", true)] - [TestCase("&", true)] - [TestCase("'", true)] - [TestCase("(", true)] - [TestCase(")", true)] - [TestCase("*", true)] - [TestCase("+", true)] - [TestCase(",", true)] - [TestCase(";", true)] - [TestCase("=", true)] - [TestCase("lorem ipsum", false)] - [TestCase("é", false)] - public void TestIsValidUriPathName(string input, bool expected) - { - bool result = input.IsValidVirtualPathName(); - Assert.AreEqual(expected, result); - } } } \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs new file mode 100644 index 000000000..57c261c7b --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -0,0 +1,98 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Test harness for the string extensions +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.UnitTests.Extensions +{ + using System; + using ImageProcessor.Web.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the string extensions + /// + [TestFixture] + public class StringExtensionsUnitTests + { + /// + /// Tests the MD5 fingerprint + /// + /// The input value + /// The expected output of the hash + [Test] + [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] + [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] + [TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] + [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] + public void TestToMd5Fingerprint(string input, string expected) + { + string result = input.ToMD5Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-1 fingerprint + /// + /// The input value + /// The expected output of the hash + [Test] + [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] + [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] + [TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] + [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] + public void TestToSHA1Fingerprint(string input, string expected) + { + string result = input.ToSHA1Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests if the value is a valid URI path name. I.E the path part of a uri. + /// + /// The value to test + /// Whether the value is correct + /// + /// The full RFC3986 does not seem to pass the test with the square brackets + /// ':' is failing for some reason in VS but not elsewhere. Could be a build issue. + /// + [Test] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] + [TestCase("-", true)] + [TestCase(".", true)] + [TestCase("_", true)] + [TestCase("~", true)] + [TestCase(":", true)] + [TestCase("/", true)] + [TestCase("?", true)] + [TestCase("#", false)] + [TestCase("[", false)] + [TestCase("]", false)] + [TestCase("@", true)] + [TestCase("!", true)] + [TestCase("$", true)] + [TestCase("&", true)] + [TestCase("'", true)] + [TestCase("(", true)] + [TestCase(")", true)] + [TestCase("*", true)] + [TestCase("+", true)] + [TestCase(",", true)] + [TestCase(";", true)] + [TestCase("=", true)] + [TestCase("lorem ipsum", false)] + [TestCase("é", false)] + public void TestIsValidUriPathName(string input, bool expected) + { + bool result = input.IsValidVirtualPathName(); + Assert.AreEqual(expected, result); + } + } +} diff --git a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj index 17c54d202..460e329b9 100644 --- a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj +++ b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj @@ -53,6 +53,7 @@ + diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs index 8e5abad95..1f868fc04 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs @@ -10,16 +10,13 @@ namespace ImageProcessor.Web.Configuration { - #region Using using System.Configuration; using System.IO; using System.Xml; - using ImageProcessor.Common.Extensions; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; - #endregion - /// /// Represents an image cache section within a configuration file. /// diff --git a/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs b/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs new file mode 100644 index 000000000..5ec1fdf4b --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs @@ -0,0 +1,143 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates a series of time saving extension methods to the class. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Extensions +{ + using System; + using System.Globalization; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + using System.Text.RegularExpressions; + + /// + /// Encapsulates a series of time saving extension methods to the class. + /// + public static class StringExtensions + { + #region Cryptography + /// + /// Creates an MD5 fingerprint of the String. + /// + /// The String instance that this method extends. + /// An MD5 fingerprint of the String. + public static string ToMD5Fingerprint(this string expression) + { + byte[] bytes = Encoding.Unicode.GetBytes(expression.ToCharArray()); + + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + byte[] hash = md5.ComputeHash(bytes); + + // Concatenate the hash bytes into one long String. + return hash.Aggregate( + new StringBuilder(32), + (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) + .ToString().ToLowerInvariant(); + } + } + + /// + /// Creates an SHA1 fingerprint of the String. + /// + /// The String instance that this method extends. + /// An SHA1 fingerprint of the String. + public static string ToSHA1Fingerprint(this string expression) + { + byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); + + using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) + { + byte[] hash = sha1.ComputeHash(bytes); + + // Concatenate the hash bytes into one long String. + return hash.Aggregate( + new StringBuilder(40), + (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) + .ToString().ToLowerInvariant(); + } + } + #endregion + + #region Numbers + /// + /// Creates an array of integers scraped from the String. + /// + /// The String instance that this method extends. + /// An array of integers scraped from the String. + public static int[] ToPositiveIntegerArray(this string expression) + { + if (string.IsNullOrWhiteSpace(expression)) + { + throw new ArgumentNullException("expression"); + } + + Regex regex = new Regex(@"[\d+]+(?=[,-])|[\d+]+(?![,-])", RegexOptions.Compiled); + + MatchCollection matchCollection = regex.Matches(expression); + + // Get the collections. + int count = matchCollection.Count; + int[] matches = new int[count]; + + // Loop and parse the int values. + for (int i = 0; i < count; i++) + { + matches[i] = int.Parse(matchCollection[i].Value, CultureInfo.InvariantCulture); + } + + return matches; + } + + /// + /// Creates an array of floats scraped from the String. + /// + /// The String instance that this method extends. + /// An array of floats scraped from the String. + public static float[] ToPositiveFloatArray(this string expression) + { + if (string.IsNullOrWhiteSpace(expression)) + { + throw new ArgumentNullException("expression"); + } + + Regex regex = new Regex(@"[\d+\.]+(?=[,-])|[\d+\.]+(?![,-])", RegexOptions.Compiled); + + MatchCollection matchCollection = regex.Matches(expression); + + // Get the collections. + int count = matchCollection.Count; + float[] matches = new float[count]; + + // Loop and parse the int values. + for (int i = 0; i < count; i++) + { + matches[i] = float.Parse(matchCollection[i].Value, CultureInfo.InvariantCulture); + } + + return matches; + } + #endregion + + #region Files and Paths + /// + /// Checks the string to see whether the value is a valid virtual path name. + /// + /// The String instance that this method extends. + /// True if the given string is a valid virtual path name + public static bool IsValidVirtualPathName(this string expression) + { + Uri uri; + + return Uri.TryCreate(expression, UriKind.Relative, out uri) && uri.IsWellFormedOriginalString(); + } + #endregion + } +} diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index d70e71867..db378fae4 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -29,9 +29,9 @@ namespace ImageProcessor.Web.HttpModules using System.Web.Hosting; using System.Web.Security; - using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Caching; using ImageProcessor.Web.Configuration; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; #endregion diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 2f5e77f23..40bd16bc7 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -54,6 +54,7 @@ + diff --git a/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs b/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs index 763697ef0..e37480ff0 100644 --- a/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs @@ -1,4 +1,13 @@ - +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates a series of time saving extension methods to the class. +// +// -------------------------------------------------------------------------------------------------------------------- + namespace ImageProcessor.Common.Extensions { using System; @@ -38,4 +47,4 @@ namespace ImageProcessor.Common.Extensions } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Common/Extensions/StringExtensions.cs b/src/ImageProcessor/Common/Extensions/StringExtensions.cs index fd7d54139..f315df797 100644 --- a/src/ImageProcessor/Common/Extensions/StringExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/StringExtensions.cs @@ -12,9 +12,6 @@ namespace ImageProcessor.Common.Extensions { using System; using System.Globalization; - using System.Linq; - using System.Security.Cryptography; - using System.Text; using System.Text.RegularExpressions; /// @@ -22,93 +19,6 @@ namespace ImageProcessor.Common.Extensions /// public static class StringExtensions { - #region Cryptography - /// - /// Creates an MD5 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An MD5 fingerprint of the String. - public static string ToMD5Fingerprint(this string expression) - { - byte[] bytes = Encoding.Unicode.GetBytes(expression.ToCharArray()); - - using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) - { - byte[] hash = md5.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(32), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - - /// - /// Creates an SHA1 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An SHA1 fingerprint of the String. - public static string ToSHA1Fingerprint(this string expression) - { - byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); - - using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) - { - byte[] hash = sha1.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(40), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - - /// - /// Creates an SHA256 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An SHA256 fingerprint of the String. - public static string ToSHA256Fingerprint(this string expression) - { - byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); - - using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) - { - byte[] hash = sha256.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(64), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - - /// - /// Creates an SHA512 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An SHA256 fingerprint of the String. - public static string ToSHA512Fingerprint(this string expression) - { - byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); - - using (SHA512CryptoServiceProvider sha512 = new SHA512CryptoServiceProvider()) - { - byte[] hash = sha512.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(70), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - #endregion - - #region Numbers /// /// Creates an array of integers scraped from the String. /// @@ -166,20 +76,5 @@ namespace ImageProcessor.Common.Extensions return matches; } - #endregion - - #region Files and Paths - /// - /// Checks the string to see whether the value is a valid virtual path name. - /// - /// The String instance that this method extends. - /// True if the given string is a valid virtual path name - public static bool IsValidVirtualPathName(this string expression) - { - Uri uri; - - return Uri.TryCreate(expression, UriKind.Relative, out uri) && uri.IsWellFormedOriginalString(); - } - #endregion } } diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index b7650d099..826ddf42f 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -298,20 +298,14 @@ namespace ImageProcessor.Imaging.Formats this.WriteByte(0); // Pixel aspect ratio this.WriteColorTable(sourceGif); - // The different browsers interpret the spec differently when adding a loop. - // If the loop count is one IE and FF < 3 (incorrectly) loop an extra number of times. - // Removing the Netscape header should fix this. - if (count > -1 && count != 1) - { - // Application Extension Header - this.WriteShort(ApplicationExtensionBlockIdentifier); - this.WriteByte(ApplicationBlockSize); - this.WriteString(ApplicationIdentification); - this.WriteByte(3); // Application block length - this.WriteByte(1); - this.WriteShort(count); // Repeat count for images. - this.WriteByte(0); // Terminator - } + // Application Extension Header + this.WriteShort(ApplicationExtensionBlockIdentifier); + this.WriteByte(ApplicationBlockSize); + this.WriteString(ApplicationIdentification); + this.WriteByte(3); // Application block length + this.WriteByte(1); + this.WriteShort(count); // Repeat count for images. + this.WriteByte(0); // Terminator } /// diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index f7ff73c66..ae5fd05c3 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -75,7 +75,7 @@ namespace ImageProcessor.Imaging.Formats { base.ApplyProcessor(processor, factory); - // Set the property item information from any Exif metadata. + // Set the property item information from any Exif metadata. // We do this here so that they can be changed between processor methods. if (factory.PreserveExifData) { diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs index 8aaff3432..574bd1e8f 100644 --- a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs +++ b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs @@ -18,6 +18,12 @@ namespace ImageProcessor.Imaging.Formats /// internal static class NativeMethods { + /// + /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method. + /// Clunky I know but I couldn't get dynamic methods to work. + /// + private static readonly bool Is64Bit = Environment.Is64BitProcess; + #region WebP /// /// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant diff --git a/src/ImageProcessor/Settings.StyleCop b/src/ImageProcessor/Settings.StyleCop index 29b381707..085067600 100644 --- a/src/ImageProcessor/Settings.StyleCop +++ b/src/ImageProcessor/Settings.StyleCop @@ -4,6 +4,7 @@ bitstream dd ddd + dllimport gps mmmm orig