public void IdenticonRequest_v200BackwardCompatiblity() { var url1 = new IdenticonRequest { Hash = HashGenerator.ComputeHash("Hello", "SHA1"), Size = 741, Style = new IdenticonStyle { Padding = 0.3f, BackColor = Color.Bisque, ColorLightness = Range.Create(0.25f, 0.75f), GrayscaleLightness = Range.Create(0, 1f), ColorSaturation = 0.4f, GrayscaleSaturation = 0.1f, Hues = new HueCollection { 1.5f, -0.25f, 0.8f } } }; var text = url1.ToString(); Assert.IsTrue(OldIdenticonRequest.TryParse(text, out var url2)); Assert.AreEqual(url1.Format, url2.Format); Assert.AreEqual(url1.Style.BackColor.ToRgba(), url2.Style.BackColor.ToRgba()); AssertAreAlmostEqual(url1.Style.Padding, url2.Style.Padding); AssertAreAlmostEqual(url1.Style.ColorLightness.From, url2.Style.ColorLightness.From); AssertAreAlmostEqual(url1.Style.ColorLightness.To, url2.Style.ColorLightness.To); AssertAreAlmostEqual(url1.Style.GrayscaleLightness.From, url2.Style.GrayscaleLightness.From); AssertAreAlmostEqual(url1.Style.GrayscaleLightness.To, url2.Style.GrayscaleLightness.To); #pragma warning disable 0618 AssertAreAlmostEqual(url1.Style.ColorSaturation, url2.Style.Saturation); #pragma warning restore 0618 AssertAreAlmostEqual(url1.Style.ColorSaturation, url2.Style.ColorSaturation); AssertAreAlmostEqual(IdenticonStyle.DefaultGrayscaleSaturation, url2.Style.GrayscaleSaturation); Assert.AreEqual(0, url2.Style.Hues.Count); Assert.AreEqual(url1.Size, url2.Size); }
/// <summary> /// Tries to parse a request string serialized by <see cref="ToString"/>. /// </summary> /// <param name="requestString">The request string.</param> /// <param name="request">The parsed request if succeeded.</param> public static bool TryParse(string requestString, out OldIdenticonRequest request) { if (requestString == null || requestString.Length == 0 || requestString.Length > 50) { goto InvalidRequest; } var base64 = requestString.ToCharArray(); var offset = base64[0] == '?' ? 1 : 0; for (var i = offset; i < base64.Length; i++) { switch (base64[i]) { case '-': base64[i] = '='; break; case '_': base64[i] = '/'; break; case '~': base64[i] = '+'; break; } } byte[] data; try { data = Convert.FromBase64CharArray(base64, offset, base64.Length - offset); } catch { goto InvalidRequest; } var checksum = ComputeChecksum(data, 1, data.Length - 1); if (checksum != data[0]) { goto InvalidRequest; } request = new OldIdenticonRequest(); try { using (var dataStream = new MemoryStream(data, 1, data.Length - 1)) { using (var reader = new BinaryReader(dataStream)) { // Size var size = reader.ReadByte(); request.size = size == 255 ? reader.ReadUInt16() : size < DefaultSizes.Length ? DefaultSizes[size] : (size - DefaultSizes.Length) * 5; // Flags: // Bit 0: explicit style (bool) // Bit 1-3: image format (int) var flags = reader.ReadByte(); // Format request.Format = (ExportImageFormat)((flags >> 1) & 0b111); // Style var explicitStyle = (flags & 0b1) == 0b1; if (explicitStyle) { // By limiting the number of decimals we are limiting // the rounding error created by the transformation // from and to a byte. const int DecimalPrecision = 3; var padding = (float)Math.Round( reader.ReadByte() / 637f, DecimalPrecision); var a = reader.ReadByte(); var r = reader.ReadByte(); var g = reader.ReadByte(); var b = reader.ReadByte(); var grayscaleLightnessFrom = (float)Math.Round( reader.ReadByte() / 255f, DecimalPrecision); var grayscaleLightnessTo = (float)Math.Round( reader.ReadByte() / 255f, DecimalPrecision); var colorLightnessFrom = (float)Math.Round( reader.ReadByte() / 255f, DecimalPrecision); var colorLightnessTo = (float)Math.Round( reader.ReadByte() / 255f, DecimalPrecision); var saturation = (float)Math.Round( reader.ReadByte() / 255f, DecimalPrecision); request.style = new IdenticonStyle { Padding = padding, BackColor = Color.FromArgb(a, r, g, b), ColorLightness = Range.Create(colorLightnessFrom, colorLightnessTo), GrayscaleLightness = Range.Create(grayscaleLightnessFrom, grayscaleLightnessTo), #pragma warning disable 0618 Saturation = saturation #pragma warning restore 0618 }; } // Hash request.Hash = reader.ReadBytes(10); } } } catch (EndOfStreamException) { goto InvalidRequest; } // Protect against too large requests if (request.size > 1000) { goto InvalidRequest; } return(true); InvalidRequest: request = null; return(false); }