diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index d448cf7838..dba26bd809 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -21,6 +21,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public const string FileVersion = "89a"; + /// + /// The ASCII encoded bytes used to identify the GIF file. + /// + internal static readonly byte[] MagicNumber = { 71, 73, 70, 56, 57, 97 }; // GIF89a + /// /// The extension block introducer !. /// @@ -41,6 +46,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public const string ApplicationIdentification = "NETSCAPE2.0"; + /// + /// The ASCII encoded application identification bytes. + /// + internal static readonly byte[] ApplicationIdentificationBytes = Encoding.UTF8.GetBytes(ApplicationIdentification); + /// /// The application block size. /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 57bb3d09a7..7550d0669a 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The writer to write to the stream with. private void WriteHeader(EndianBinaryWriter writer) { - writer.Write((GifConstants.FileType + GifConstants.FileVersion).ToCharArray()); + writer.Write(GifConstants.MagicNumber, 0, GifConstants.MagicNumber.Length); } /// @@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.Formats.Gif writer.Write(this.buffer, 0, 3); - writer.Write(GifConstants.ApplicationIdentification.ToCharArray()); // NETSCAPE2.0 + writer.Write(GifConstants.ApplicationIdentificationBytes, 0, GifConstants.ApplicationIdentificationBytes.Length); // NETSCAPE2.0 writer.Write((byte)3); // Application block length writer.Write((byte)1); // Data sub-block index (always 1) diff --git a/src/ImageSharp/IO/EndianBinaryReader.cs b/src/ImageSharp/IO/EndianBinaryReader.cs index 25cd0adcef..6454ff2506 100644 --- a/src/ImageSharp/IO/EndianBinaryReader.cs +++ b/src/ImageSharp/IO/EndianBinaryReader.cs @@ -14,26 +14,11 @@ namespace SixLabors.ImageSharp.IO /// internal class EndianBinaryReader : IDisposable { - /// - /// Decoder to use for string conversions. - /// - private readonly Decoder decoder; - /// /// Buffer used for temporary storage before conversion into primitives /// private readonly byte[] storageBuffer = new byte[16]; - /// - /// Buffer used for temporary storage when reading a single character - /// - private readonly char[] charBuffer = new char[1]; - - /// - /// Minimum number of bytes used to encode a character - /// - private readonly int minBytesPerChar; - /// /// Whether or not this reader has been disposed yet. /// @@ -44,21 +29,6 @@ namespace SixLabors.ImageSharp.IO /// private readonly Endianness endianness; - /// - /// Initializes a new instance of the class. - /// Modeled after with endian support. - /// - /// - /// Endianness to use when reading data - /// - /// - /// Stream to read data from - /// - public EndianBinaryReader(Endianness endianness, Stream stream) - : this(endianness, stream, Encoding.UTF8) - { - } - /// /// Initializes a new instance of the class. /// Constructs a new binary reader with the given bit converter, reading @@ -66,30 +36,15 @@ namespace SixLabors.ImageSharp.IO /// /// Endianness to use when reading data /// Stream to read data from - /// Encoding to use when reading character data - public EndianBinaryReader(Endianness endianness, Stream stream, Encoding encoding) + public EndianBinaryReader(Endianness endianness, Stream stream) { Guard.NotNull(stream, nameof(stream)); - Guard.NotNull(encoding, nameof(encoding)); Guard.IsTrue(stream.CanRead, nameof(stream), "Stream isn't readable"); this.BaseStream = stream; - this.Encoding = encoding; - this.decoder = encoding.GetDecoder(); this.endianness = endianness; - this.minBytesPerChar = 1; - - if (encoding is UnicodeEncoding) - { - this.minBytesPerChar = 2; - } } - /// - /// Gets the encoding used to read strings - /// - public Encoding Encoding { get; } - /// /// Gets the underlying stream of the EndianBinaryReader. /// @@ -253,92 +208,6 @@ namespace SixLabors.ImageSharp.IO return *((double*)&value); } - /// - /// Reads a single character from the stream, using the character encoding for - /// this reader. If no characters have been fully read by the time the stream ends, - /// -1 is returned. - /// - /// The character read, or -1 for end of stream. - public int Read() - { - int charsRead = this.Read(this.charBuffer, 0, 1); - if (charsRead == 0) - { - return -1; - } - else - { - return this.charBuffer[0]; - } - } - - /// - /// Reads the specified number of characters into the given buffer, starting at - /// the given index. - /// - /// The buffer to copy data into - /// The first index to copy data into - /// The number of characters to read - /// The number of characters actually read. This will only be less than - /// the requested number of characters if the end of the stream is reached. - /// - public int Read(char[] data, int index, int count) - { - this.CheckDisposed(); - - Guard.NotNull(this.storageBuffer, nameof(this.storageBuffer)); - Guard.MustBeGreaterThanOrEqualTo(index, 0, nameof(index)); - Guard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count)); - Guard.IsFalse(count + index > data.Length, nameof(data.Length), "Not enough space in buffer for specified number of characters starting at specified index."); - - int read = 0; - bool firstTime = true; - - // Use the normal buffer if we're only reading a small amount, otherwise - // use at most 4K at a time. - byte[] byteBuffer = this.storageBuffer; - - if (byteBuffer.Length < count * this.minBytesPerChar) - { - byteBuffer = new byte[4096]; - } - - while (read < count) - { - int amountToRead; - - // First time through we know we haven't previously read any data - if (firstTime) - { - amountToRead = count * this.minBytesPerChar; - firstTime = false; - } - else - { - // After that we can only assume we need to fully read 'chars left -1' characters - // and a single byte of the character we may be in the middle of - amountToRead = ((count - read - 1) * this.minBytesPerChar) + 1; - } - - if (amountToRead > byteBuffer.Length) - { - amountToRead = byteBuffer.Length; - } - - int bytesRead = this.TryReadInternal(byteBuffer, amountToRead); - if (bytesRead == 0) - { - return read; - } - - int decoded = this.decoder.GetChars(byteBuffer, 0, bytesRead, data, index); - read += decoded; - index += decoded; - } - - return read; - } - /// /// Reads the specified number of bytes into the given buffer, starting at /// the given index. @@ -421,84 +290,6 @@ namespace SixLabors.ImageSharp.IO return ret; } - /// - /// Reads a 7-bit encoded integer from the stream. This is stored with the least significant - /// information first, with 7 bits of information per byte of value, and the top - /// bit as a continuation flag. This method is not affected by the endianness - /// of the bit converter. - /// - /// The 7-bit encoded integer read from the stream. - public int Read7BitEncodedInt() - { - this.CheckDisposed(); - - int ret = 0; - for (int shift = 0; shift < 35; shift += 7) - { - int b = this.BaseStream.ReadByte(); - if (b == -1) - { - throw new EndOfStreamException(); - } - - ret = ret | ((b & 0x7f) << shift); - if ((b & 0x80) == 0) - { - return ret; - } - } - - // Still haven't seen a byte with the high bit unset? Dodgy data. - throw new IOException("Invalid 7-bit encoded integer in stream."); - } - - /// - /// Reads a 7-bit encoded integer from the stream. This is stored with the most significant - /// information first, with 7 bits of information per byte of value, and the top - /// bit as a continuation flag. This method is not affected by the endianness - /// of the bit converter. - /// - /// The 7-bit encoded integer read from the stream. - public int ReadBigEndian7BitEncodedInt() - { - this.CheckDisposed(); - - int ret = 0; - for (int i = 0; i < 5; i++) - { - int b = this.BaseStream.ReadByte(); - if (b == -1) - { - throw new EndOfStreamException(); - } - - ret = (ret << 7) | (b & 0x7f); - if ((b & 0x80) == 0) - { - return ret; - } - } - - // Still haven't seen a byte with the high bit unset? Dodgy data. - throw new IOException("Invalid 7-bit encoded integer in stream."); - } - - /// - /// Reads a length-prefixed string from the stream, using the encoding for this reader. - /// A 7-bit encoded integer is first read, which specifies the number of bytes - /// to read from the stream. These bytes are then converted into a string with - /// the encoding for this reader. - /// - /// The string read from the stream. - public string ReadString() - { - int bytesToRead = this.Read7BitEncodedInt(); - - byte[] data = new byte[bytesToRead]; - this.ReadInternal(data, bytesToRead); - return this.Encoding.GetString(data, 0, data.Length); - } - /// /// Disposes of the underlying stream. /// diff --git a/src/ImageSharp/IO/EndianBinaryWriter.cs b/src/ImageSharp/IO/EndianBinaryWriter.cs index b8cd2cad52..9c42f0b694 100644 --- a/src/ImageSharp/IO/EndianBinaryWriter.cs +++ b/src/ImageSharp/IO/EndianBinaryWriter.cs @@ -4,7 +4,6 @@ using System; using System.Buffers.Binary; using System.IO; -using System.Text; namespace SixLabors.ImageSharp.IO { @@ -18,11 +17,6 @@ namespace SixLabors.ImageSharp.IO /// private readonly byte[] buffer = new byte[16]; - /// - /// Buffer used for Write(char) - /// - private readonly char[] charBuffer = new char[1]; - /// /// The endianness used to write the data /// @@ -33,42 +27,21 @@ namespace SixLabors.ImageSharp.IO /// private bool disposed; - /// - /// Initializes a new instance of the class - /// with the given bit converter, writing to the given stream, using UTF-8 encoding. - /// - /// Endianness to use when writing data - /// Stream to write data to - public EndianBinaryWriter(Endianness endianness, Stream stream) - : this(endianness, stream, Encoding.UTF8) - { - } - /// /// Initializes a new instance of the class /// with the given bit converter, writing to the given stream, using the given encoding. /// /// Endianness to use when writing data /// Stream to write data to - /// - /// Encoding to use when writing character data - /// - public EndianBinaryWriter(Endianness endianness, Stream stream, Encoding encoding) + public EndianBinaryWriter(Endianness endianness, Stream stream) { Guard.NotNull(stream, nameof(stream)); - Guard.NotNull(stream, nameof(encoding)); Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable"); this.BaseStream = stream; - this.Encoding = encoding; this.endianness = endianness; } - /// - /// Gets the encoding used to write strings - /// - public Encoding Encoding { get; } - /// /// Gets the underlying stream of the EndianBinaryWriter. /// @@ -291,71 +264,6 @@ namespace SixLabors.ImageSharp.IO this.BaseStream.Write(value, offset, count); } - /// - /// Writes a single character to the stream, using the encoding for this writer. - /// - /// The value to write - public void Write(char value) - { - this.charBuffer[0] = value; - this.Write(this.charBuffer); - } - - /// - /// Writes an array of characters to the stream, using the encoding for this writer. - /// - /// An array containing the characters to write - /// value is null - public void Write(char[] value) - { - Guard.NotNull(value, nameof(value)); - - this.CheckDisposed(); - byte[] data = this.Encoding.GetBytes(value, 0, value.Length); - this.WriteInternal(data, data.Length); - } - - /// - /// Writes a length-prefixed string to the stream, using the encoding for this writer. - /// - /// The value to write. Must not be null. - /// value is null - public void Write(string value) - { - Guard.NotNull(value, nameof(value)); - - this.CheckDisposed(); - byte[] data = this.Encoding.GetBytes(value); - this.Write7BitEncodedInt(data.Length); - this.WriteInternal(data, data.Length); - } - - /// - /// Writes a 7-bit encoded integer from the stream. This is stored with the least significant - /// information first, with 7 bits of information per byte of value, and the top - /// bit as a continuation flag. - /// - /// The 7-bit encoded integer to write to the stream - public void Write7BitEncodedInt(int value) - { - this.CheckDisposed(); - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "Value must be greater than or equal to 0."); - } - - int index = 0; - while (value >= 128) - { - this.buffer[index++] = (byte)((value & 0x7f) | 0x80); - value = value >> 7; - index++; - } - - this.buffer[index++] = (byte)value; - this.BaseStream.Write(this.buffer, 0, index); - } - /// /// Disposes of the underlying stream. /// diff --git a/tests/ImageSharp.Tests/IO/EndianBinaryReaderTests.cs b/tests/ImageSharp.Tests/IO/EndianBinaryReaderTests.cs deleted file mode 100644 index fcf484f49d..0000000000 --- a/tests/ImageSharp.Tests/IO/EndianBinaryReaderTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.IO; -using System.Text; -using SixLabors.ImageSharp.IO; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.IO -{ - /// - /// The endian binary reader tests. - /// - public class EndianBinaryReaderTests - { - /// - /// The test string. - /// - private const string TestString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz"; - - /// - /// The test bytes. - /// - private static readonly byte[] TestBytes = Encoding.ASCII.GetBytes(TestString); - - /// - /// Tests to ensure that the reader can read beyond internal buffer size. - /// - [Fact] - public void ReadCharsBeyondInternalBufferSize() - { - var stream = new MemoryStream(TestBytes); - using (var subject = new EndianBinaryReader(Endianness.LittleEndian, stream)) - { - char[] chars = new char[TestString.Length]; - subject.Read(chars, 0, chars.Length); - Assert.Equal(TestString, new string(chars)); - } - } - - /// - /// Tests to ensure that the reader cannot read beyond the provided buffer size. - /// - [Fact] - public void ReadCharsBeyondProvidedBufferSize() - { - Assert.Throws( - () => - { - var stream = new MemoryStream(TestBytes); - using (var subject = new EndianBinaryReader(Endianness.LittleEndian, stream)) - { - char[] chars = new char[TestString.Length - 1]; - - subject.Read(chars, 0, TestString.Length); - } - }); - } - } -}