From fd1e241e787e176aaa279dd95639edb1295d346b Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Sat, 27 Jan 2024 23:17:10 +1100 Subject: [PATCH 1/2] Spanify indexed reader classes Allows avoidance of temporary byte arrays, reduces the number of virtual calls to `GetByteInternal`, and uses conversion methods optimised by the framework (e.g. `BinaryPrimitives`). --- .../IO/IndexedReaderTestBase.cs | 8 +- MetadataExtractor/IO/ByteArrayReader.cs | 17 +- .../IO/IndexedCapturingReader.cs | 25 +- MetadataExtractor/IO/IndexedReader.cs | 286 +++++++++--------- MetadataExtractor/IO/IndexedSeekingReader.cs | 44 +-- .../IO/SequentialStreamReader.cs | 2 +- .../netstandard1.3/PublicAPI.Unshipped.txt | 8 +- .../netstandard2.1/PublicAPI.Unshipped.txt | 8 +- 8 files changed, 192 insertions(+), 206 deletions(-) diff --git a/MetadataExtractor.Tests/IO/IndexedReaderTestBase.cs b/MetadataExtractor.Tests/IO/IndexedReaderTestBase.cs index c1f222592..17c57c378 100644 --- a/MetadataExtractor.Tests/IO/IndexedReaderTestBase.cs +++ b/MetadataExtractor.Tests/IO/IndexedReaderTestBase.cs @@ -188,7 +188,9 @@ public void GetFloat32() var reader = CreateReader(0x7f, 0xc0, 0x00, 0x00); - Assert.True(float.IsNaN(reader.GetFloat32(0))); + float f = reader.GetFloat32(0); + + Assert.True(float.IsNaN(f), $"Expected NaN, got {f}."); } [Fact] @@ -199,7 +201,9 @@ public void GetFloat64() var reader = CreateReader(0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); - Assert.True(double.IsNaN(reader.GetDouble64(0))); + double d = reader.GetDouble64(0); + + Assert.True(double.IsNaN(d), $"Expected NaN, got {d}."); } [Fact] diff --git a/MetadataExtractor/IO/ByteArrayReader.cs b/MetadataExtractor/IO/ByteArrayReader.cs index f29bd8701..9ea7816d3 100644 --- a/MetadataExtractor/IO/ByteArrayReader.cs +++ b/MetadataExtractor/IO/ByteArrayReader.cs @@ -33,9 +33,11 @@ public ByteArrayReader(byte[] buffer, int baseOffset = 0, bool isMotorolaByteOrd public override long Length => _buffer.Length - _baseOffset; - protected override byte GetByteInternal(int index) + public override void GetBytes(int index, Span bytes) { - return _buffer[index + _baseOffset]; + ValidateIndex(index, bytes.Length); + + _buffer.AsSpan().Slice(index + _baseOffset, bytes.Length).CopyTo(bytes); } protected override void ValidateIndex(int index, int bytesRequested) @@ -44,21 +46,12 @@ protected override void ValidateIndex(int index, int bytesRequested) throw new BufferBoundsException(ToUnshiftedOffset(index), bytesRequested, _buffer.Length); } - protected override bool IsValidIndex(int index, int bytesRequested) + private bool IsValidIndex(int index, int bytesRequested) { return bytesRequested >= 0 && index >= 0 && index + (long)bytesRequested - 1L < Length; } - - public override byte[] GetBytes(int index, int count) - { - ValidateIndex(index, count); - - var bytes = new byte[count]; - Array.Copy(_buffer, index + _baseOffset, bytes, 0, count); - return bytes; - } } } diff --git a/MetadataExtractor/IO/IndexedCapturingReader.cs b/MetadataExtractor/IO/IndexedCapturingReader.cs index 5eb849be7..a49a8c6c6 100644 --- a/MetadataExtractor/IO/IndexedCapturingReader.cs +++ b/MetadataExtractor/IO/IndexedCapturingReader.cs @@ -80,7 +80,7 @@ protected override void ValidateIndex(int index, int bytesRequested) } } - protected override bool IsValidIndex(int index, int bytesRequested) + private bool IsValidIndex(int index, int bytesRequested) { if (index < 0 || bytesRequested < 0) return false; @@ -143,19 +143,11 @@ private void GetPosition(int index, out int chunkIndex, out int innerIndex) #endif } - protected override byte GetByteInternal(int index) + public override void GetBytes(int index, Span bytes) { - GetPosition(index, out int chunkIndex, out int innerIndex); - var chunk = _chunks[chunkIndex]; - return chunk[innerIndex]; - } - - public override byte[] GetBytes(int index, int count) - { - ValidateIndex(index, count); + ValidateIndex(index, bytes.Length); - var bytes = new byte[count]; - var remaining = count; + var remaining = bytes.Length; var fromIndex = index; var toIndex = 0; while (remaining != 0) @@ -163,12 +155,11 @@ public override byte[] GetBytes(int index, int count) GetPosition(fromIndex, out int fromChunkIndex, out int fromInnerIndex); var length = Math.Min(remaining, _chunkLength - fromInnerIndex); var chunk = _chunks[fromChunkIndex]; - Array.Copy(chunk, fromInnerIndex, bytes, toIndex, length); + chunk.AsSpan().Slice(fromInnerIndex, length).CopyTo(bytes.Slice(toIndex, length)); remaining -= length; fromIndex += length; toIndex += length; } - return bytes; } public override IndexedReader WithByteOrder(bool isMotorolaByteOrder) => isMotorolaByteOrder == IsMotorolaByteOrder ? this : new ShiftedIndexedCapturingReader(this, 0, isMotorolaByteOrder); @@ -196,14 +187,10 @@ public ShiftedIndexedCapturingReader(IndexedCapturingReader baseReader, int base public override int ToUnshiftedOffset(int localOffset) => localOffset + _baseOffset; - protected override byte GetByteInternal(int index) => _baseReader.GetByteInternal(_baseOffset + index); - - public override byte[] GetBytes(int index, int count) => _baseReader.GetBytes(_baseOffset + index, count); + public override void GetBytes(int index, Span bytes) => _baseReader.GetBytes(_baseOffset + index, bytes); protected override void ValidateIndex(int index, int bytesRequested) => _baseReader.ValidateIndex(index + _baseOffset, bytesRequested); - protected override bool IsValidIndex(int index, int bytesRequested) => _baseReader.IsValidIndex(index + _baseOffset, bytesRequested); - public override long Length => _baseReader.Length - _baseOffset; } } diff --git a/MetadataExtractor/IO/IndexedReader.cs b/MetadataExtractor/IO/IndexedReader.cs index 13a537070..ed610cbb0 100644 --- a/MetadataExtractor/IO/IndexedReader.cs +++ b/MetadataExtractor/IO/IndexedReader.cs @@ -1,7 +1,7 @@ // Copyright (c) Drew Noakes and contributors. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. -// TODO always read bytes in order which may assist memory read patterns +using System.Buffers.Binary; namespace MetadataExtractor.IO { @@ -17,13 +17,8 @@ namespace MetadataExtractor.IO /// . /// /// Drew Noakes https://drewnoakes.com - public abstract class IndexedReader + public abstract class IndexedReader(bool isMotorolaByteOrder) { - protected IndexedReader(bool isMotorolaByteOrder) - { - IsMotorolaByteOrder = isMotorolaByteOrder; - } - /// Get the byte order of this reader. /// /// @@ -31,7 +26,7 @@ protected IndexedReader(bool isMotorolaByteOrder) /// false for Intel (or little) endianness, with LSB before MSB. /// /// - public bool IsMotorolaByteOrder { get; } + public bool IsMotorolaByteOrder { get; } = isMotorolaByteOrder; public abstract IndexedReader WithByteOrder(bool isMotorolaByteOrder); @@ -39,13 +34,6 @@ protected IndexedReader(bool isMotorolaByteOrder) public abstract int ToUnshiftedOffset(int localOffset); - /// Gets the byte value at the specified byte index. - /// Implementations should assume has already been validated. - /// The index from which to read the byte - /// The read byte value - /// if the byte is unable to be read - protected abstract byte GetByteInternal(int index); - /// Returns the required number of bytes from the specified index from the underlying source. /// The index from which the bytes begins in the underlying source /// The number of bytes to be returned @@ -53,7 +41,23 @@ protected IndexedReader(bool isMotorolaByteOrder) /// index or count are negative /// if the requested bytes extend beyond the end of the underlying data source /// if the byte is unable to be read - public abstract byte[] GetBytes(int index, int count); + public byte[] GetBytes(int index, int count) + { + ValidateIndex(index, count); + + var bytes = new byte[count]; + + GetBytes(index, bytes.AsSpan()); + + return bytes; + } + + /// + /// Copies bytes from the underlying source into . + /// + /// The index from which the bytes begins in the underlying source + /// A span of bytes to copy to. The length of this span determines how many bytes will be copied. + public abstract void GetBytes(int index, Span bytes); /// /// Ensures that the buffered bytes extend to cover the specified index. If not, an attempt is made @@ -67,9 +71,6 @@ protected IndexedReader(bool isMotorolaByteOrder) /// if the stream ends before the required number of bytes are acquired protected abstract void ValidateIndex(int index, int bytesRequested); - /// - protected abstract bool IsValidIndex(int index, int bytesRequested); - /// Returns the length of the data source in bytes. /// /// This is a simple operation for implementations (such as and @@ -91,9 +92,12 @@ public bool GetBit(int index) { var byteIndex = index / 8; var bitIndex = index % 8; - ValidateIndex(byteIndex, 1); - var b = GetByteInternal(byteIndex); - return ((b >> bitIndex) & 1) == 1; + + Span bytes = stackalloc byte[1]; + + GetBytes(byteIndex, bytes); + + return ((bytes[0] >> bitIndex) & 1) == 1; } /// Gets the byte value at the specified byte index. @@ -107,8 +111,11 @@ public bool GetBit(int index) /// if the byte is unable to be read public byte GetByte(int index) { - ValidateIndex(index, 1); - return GetByteInternal(index); + Span bytes = stackalloc byte[1]; + + GetBytes(index, bytes); + + return bytes[0]; } /// Returns a signed 8-bit int calculated from one byte of data at the specified index. @@ -117,8 +124,7 @@ public byte GetByte(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public sbyte GetSByte(int index) { - ValidateIndex(index, 1); - return unchecked((sbyte)GetByteInternal(index)); + return unchecked((sbyte)GetByte(index)); } #pragma warning disable format @@ -129,18 +135,13 @@ public sbyte GetSByte(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public ushort GetUInt16(int index) { - ValidateIndex(index, 2); - if (IsMotorolaByteOrder) - { - // Motorola - MSB first - return (ushort) - (GetByteInternal(index ) << 8 | - GetByteInternal(index + 1)); - } - // Intel ordering - LSB first - return (ushort) - (GetByteInternal(index + 1) << 8 | - GetByteInternal(index )); + Span bytes = stackalloc byte[2]; + + GetBytes(index, bytes); + + return IsMotorolaByteOrder + ? BinaryPrimitives.ReadUInt16BigEndian(bytes) + : BinaryPrimitives.ReadUInt16LittleEndian(bytes); } /// Returns a signed 16-bit int calculated from two bytes of data at the specified index (MSB, LSB). @@ -149,18 +150,13 @@ public ushort GetUInt16(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public short GetInt16(int index) { - ValidateIndex(index, 2); - if (IsMotorolaByteOrder) - { - // Motorola - MSB first - return (short) - (GetByteInternal(index ) << 8 | - GetByteInternal(index + 1)); - } - // Intel ordering - LSB first - return (short) - (GetByteInternal(index + 1) << 8 | - GetByteInternal(index)); + Span bytes = stackalloc byte[2]; + + GetBytes(index, bytes); + + return IsMotorolaByteOrder + ? BinaryPrimitives.ReadInt16BigEndian(bytes) + : BinaryPrimitives.ReadInt16LittleEndian(bytes); } /// Get a 24-bit unsigned integer from the buffer, returning it as an int. @@ -169,20 +165,24 @@ public short GetInt16(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public int GetInt24(int index) { - ValidateIndex(index, 3); + Span bytes = stackalloc byte[3]; + + GetBytes(index, bytes); + if (IsMotorolaByteOrder) { - // Motorola - MSB first (big endian) return - GetByteInternal(index ) << 16 | - GetByteInternal(index + 1) << 8 | - GetByteInternal(index + 2); + bytes[0] << 16 | + bytes[1] << 8 | + bytes[2]; + } + else + { + return + bytes[2] << 16 | + bytes[1] << 8 | + bytes[0]; } - // Intel ordering - LSB first (little endian) - return - GetByteInternal(index + 2) << 16 | - GetByteInternal(index + 1) << 8 | - GetByteInternal(index ); } /// Get a 32-bit unsigned integer from the buffer, returning it as a long. @@ -191,22 +191,13 @@ public int GetInt24(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public uint GetUInt32(int index) { - ValidateIndex(index, 4); - if (IsMotorolaByteOrder) - { - // Motorola - MSB first (big endian) - return (uint) - (GetByteInternal(index ) << 24 | - GetByteInternal(index + 1) << 16 | - GetByteInternal(index + 2) << 8 | - GetByteInternal(index + 3)); - } - // Intel ordering - LSB first (little endian) - return (uint) - (GetByteInternal(index + 3) << 24 | - GetByteInternal(index + 2) << 16 | - GetByteInternal(index + 1) << 8 | - GetByteInternal(index )); + Span bytes = stackalloc byte[4]; + + GetBytes(index, bytes); + + return IsMotorolaByteOrder + ? BinaryPrimitives.ReadUInt32BigEndian(bytes) + : BinaryPrimitives.ReadUInt32LittleEndian(bytes); } /// Returns a signed 32-bit integer from four bytes of data at the specified index the buffer. @@ -215,22 +206,13 @@ public uint GetUInt32(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public int GetInt32(int index) { - ValidateIndex(index, 4); - if (IsMotorolaByteOrder) - { - // Motorola - MSB first (big endian) - return - GetByteInternal(index ) << 24 | - GetByteInternal(index + 1) << 16 | - GetByteInternal(index + 2) << 8 | - GetByteInternal(index + 3); - } - // Intel ordering - LSB first (little endian) - return - GetByteInternal(index + 3) << 24 | - GetByteInternal(index + 2) << 16 | - GetByteInternal(index + 1) << 8 | - GetByteInternal(index ); + Span bytes = stackalloc byte[4]; + + GetBytes(index, bytes); + + return IsMotorolaByteOrder + ? BinaryPrimitives.ReadInt32BigEndian(bytes) + : BinaryPrimitives.ReadInt32LittleEndian(bytes); } /// Get a signed 64-bit integer from the buffer. @@ -239,30 +221,13 @@ public int GetInt32(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public long GetInt64(int index) { - ValidateIndex(index, 8); - if (IsMotorolaByteOrder) - { - // Motorola - MSB first - return - (long)GetByteInternal(index ) << 56 | - (long)GetByteInternal(index + 1) << 48 | - (long)GetByteInternal(index + 2) << 40 | - (long)GetByteInternal(index + 3) << 32 | - (long)GetByteInternal(index + 4) << 24 | - (long)GetByteInternal(index + 5) << 16 | - (long)GetByteInternal(index + 6) << 8 | - GetByteInternal(index + 7); - } - // Intel ordering - LSB first - return - (long)GetByteInternal(index + 7) << 56 | - (long)GetByteInternal(index + 6) << 48 | - (long)GetByteInternal(index + 5) << 40 | - (long)GetByteInternal(index + 4) << 32 | - (long)GetByteInternal(index + 3) << 24 | - (long)GetByteInternal(index + 2) << 16 | - (long)GetByteInternal(index + 1) << 8 | - GetByteInternal(index ); + Span bytes = stackalloc byte[8]; + + GetBytes(index, bytes); + + return IsMotorolaByteOrder + ? BinaryPrimitives.ReadInt64BigEndian(bytes) + : BinaryPrimitives.ReadInt64LittleEndian(bytes); } /// Get an unsigned 64-bit integer from the buffer. @@ -271,30 +236,13 @@ public long GetInt64(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public ulong GetUInt64(int index) { - ValidateIndex(index, 8); - if (IsMotorolaByteOrder) - { - // Motorola - MSB first - return - (ulong)GetByteInternal(index ) << 56 | - (ulong)GetByteInternal(index + 1) << 48 | - (ulong)GetByteInternal(index + 2) << 40 | - (ulong)GetByteInternal(index + 3) << 32 | - (ulong)GetByteInternal(index + 4) << 24 | - (ulong)GetByteInternal(index + 5) << 16 | - (ulong)GetByteInternal(index + 6) << 8 | - GetByteInternal(index + 7); - } - // Intel ordering - LSB first - return - (ulong)GetByteInternal(index + 7) << 56 | - (ulong)GetByteInternal(index + 6) << 48 | - (ulong)GetByteInternal(index + 5) << 40 | - (ulong)GetByteInternal(index + 4) << 32 | - (ulong)GetByteInternal(index + 3) << 24 | - (ulong)GetByteInternal(index + 2) << 16 | - (ulong)GetByteInternal(index + 1) << 8 | - GetByteInternal(index ); + Span bytes = stackalloc byte[8]; + + GetBytes(index, bytes); + + return IsMotorolaByteOrder + ? BinaryPrimitives.ReadUInt64BigEndian(bytes) + : BinaryPrimitives.ReadUInt64LittleEndian(bytes); } #pragma warning restore format @@ -307,33 +255,77 @@ public ulong GetUInt64(int index) /// the buffer does not contain enough bytes to service the request, or index is negative public float GetS15Fixed16(int index) { - ValidateIndex(index, 4); + Span bytes = stackalloc byte[4]; + + GetBytes(index, bytes); + if (IsMotorolaByteOrder) { - float res = GetByteInternal(index) << 8 | GetByteInternal(index + 1); - var d = GetByteInternal(index + 2) << 8 | GetByteInternal(index + 3); + float res = bytes[0] << 8 | bytes[1]; + var d = bytes[2] << 8 | bytes[3]; return (float)(res + d / 65536.0); } else { // this particular branch is untested - var d = GetByteInternal(index + 1) << 8 | GetByteInternal(index); - float res = GetByteInternal(index + 3) << 8 | GetByteInternal(index + 2); + var d = bytes[1] << 8 | bytes[0]; + float res = bytes[3] << 8 | bytes[2]; return (float)(res + d / 65536.0); } } /// - public float GetFloat32(int index) => BitConverter.ToSingle(BitConverter.GetBytes(GetInt32(index)), 0); + public float GetFloat32(int index) + { +#if NET45 || NETSTANDARD1_3 + return BitConverter.ToSingle(BitConverter.GetBytes(GetInt32(index)), 0); +#else + Span bytes = stackalloc byte[4]; + + GetBytes(index, bytes); + + if (IsMotorolaByteOrder) + { + bytes.Reverse(); + } + + return BitConverter.ToSingle(bytes); +#endif + } /// - public double GetDouble64(int index) => BitConverter.Int64BitsToDouble(GetInt64(index)); + public double GetDouble64(int index) + { +#if NET45 || NETSTANDARD1_3 + return BitConverter.Int64BitsToDouble(GetInt64(index)); +#else + Span bytes = stackalloc byte[8]; + + GetBytes(index, bytes); + + if (IsMotorolaByteOrder) + { + bytes.Reverse(); + } + + return BitConverter.ToDouble(bytes); +#endif + } /// public string GetString(int index, int bytesRequested, Encoding encoding) { +#if NET45 || NETSTANDARD1_3 var bytes = GetBytes(index, bytesRequested); + return encoding.GetString(bytes, 0, bytes.Length); +#else + Span bytes = bytesRequested < 256 ? stackalloc byte[bytesRequested] : new byte[bytesRequested]; + + GetBytes(index, bytes); + + return encoding.GetString(bytes); +#endif } /// diff --git a/MetadataExtractor/IO/IndexedSeekingReader.cs b/MetadataExtractor/IO/IndexedSeekingReader.cs index 7bfe6b42f..ae27d06f9 100644 --- a/MetadataExtractor/IO/IndexedSeekingReader.cs +++ b/MetadataExtractor/IO/IndexedSeekingReader.cs @@ -41,35 +41,41 @@ public IndexedSeekingReader(Stream stream, int baseOffset = 0, bool isMotorolaBy public override long Length { get; } - protected override byte GetByteInternal(int index) +#if !NETSTANDARD2_1 + private readonly byte[] _buffer = new byte[2048]; +#endif + + public override void GetBytes(int index, Span bytes) { - ValidateIndex(index, 1); + int count = bytes.Length; + + ValidateIndex(index, count); if (index + _baseOffset != _stream.Position) Seek(index); - var b = _stream.ReadByte(); + int totalBytesRead = 0; - if (b < 0) - throw new BufferBoundsException("Unexpected end of file encountered."); + while (totalBytesRead != bytes.Length) + { + var target = bytes.Slice(totalBytesRead); +#if NETSTANDARD2_1 + var bytesRead = _stream.Read(target); +#else + var len = Math.Min(bytes.Length - totalBytesRead, _buffer.Length); - return unchecked((byte)b); - } + var bytesRead = _stream.Read(_buffer, 0, len); - public override byte[] GetBytes(int index, int count) - { - ValidateIndex(index, count); - - if (index + _baseOffset != _stream.Position) - Seek(index); + _buffer.AsSpan(0, len).CopyTo(target); +#endif + if (bytesRead == 0) + throw new IOException("End of data reached."); - var bytes = new byte[count]; - var bytesRead = _stream.Read(bytes, 0, count); + totalBytesRead += bytesRead; - if (bytesRead != count) - throw new BufferBoundsException("Unexpected end of file encountered."); + Debug.Assert(totalBytesRead <= bytes.Length); + } - return bytes; } private void Seek(int index) @@ -81,7 +87,7 @@ private void Seek(int index) _stream.Seek(streamIndex, SeekOrigin.Begin); } - protected override bool IsValidIndex(int index, int bytesRequested) + private bool IsValidIndex(int index, int bytesRequested) { return bytesRequested >= 0 && diff --git a/MetadataExtractor/IO/SequentialStreamReader.cs b/MetadataExtractor/IO/SequentialStreamReader.cs index 604398197..9dc5f995e 100644 --- a/MetadataExtractor/IO/SequentialStreamReader.cs +++ b/MetadataExtractor/IO/SequentialStreamReader.cs @@ -65,7 +65,7 @@ public override void GetBytes(Span bytes) #if NETSTANDARD2_1 var bytesRead = _stream.Read(target); #else - var len = bytes.Length - totalBytesRead; + var len = Math.Min(bytes.Length - totalBytesRead, _buffer.Length); var bytesRead = _stream.Read(_buffer, 0, len); diff --git a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt index bc8200c9b..a572972f7 100644 --- a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt +++ b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt @@ -1,5 +1,5 @@ #nullable enable -abstract MetadataExtractor.IO.IndexedReader.GetByteInternal(int index) -> byte +abstract MetadataExtractor.IO.IndexedReader.GetBytes(int index, System.Span bytes) -> void abstract MetadataExtractor.IO.SequentialReader.GetBytes(System.Span bytes) -> void const MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.TagEpoch = 2 -> int const MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.TagFlags = 1 -> int @@ -68,14 +68,16 @@ MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Descriptor.NikonPi MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory.NikonPictureControl2Directory() -> void MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte +MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]! override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string! override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Directory.Name.get -> string! override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Descriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory.Name.get -> string! -override MetadataExtractor.IO.ByteArrayReader.GetByteInternal(int index) -> byte -override MetadataExtractor.IO.IndexedSeekingReader.GetByteInternal(int index) -> byte +override MetadataExtractor.IO.ByteArrayReader.GetBytes(int index, System.Span bytes) -> void +override MetadataExtractor.IO.IndexedCapturingReader.GetBytes(int index, System.Span bytes) -> void +override MetadataExtractor.IO.IndexedSeekingReader.GetBytes(int index, System.Span bytes) -> void override MetadataExtractor.IO.SequentialByteArrayReader.GetBytes(System.Span bytes) -> void override MetadataExtractor.IO.SequentialStreamReader.GetBytes(System.Span bytes) -> void static MetadataExtractor.Formats.Apple.BplistReader.IsValid(byte[]! bplist) -> bool diff --git a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt index 7aa9c939f..fc56fb047 100644 --- a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt +++ b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,5 +1,5 @@ #nullable enable -abstract MetadataExtractor.IO.IndexedReader.GetByteInternal(int index) -> byte +abstract MetadataExtractor.IO.IndexedReader.GetBytes(int index, System.Span bytes) -> void abstract MetadataExtractor.IO.SequentialReader.GetBytes(System.Span bytes) -> void const MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.TagEpoch = 2 -> int const MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.TagFlags = 1 -> int @@ -67,14 +67,16 @@ MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Descriptor.NikonPi MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory.NikonPictureControl2Directory() -> void MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte +MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]! override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string! override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Directory.Name.get -> string! override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Descriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory.Name.get -> string! -override MetadataExtractor.IO.ByteArrayReader.GetByteInternal(int index) -> byte -override MetadataExtractor.IO.IndexedSeekingReader.GetByteInternal(int index) -> byte +override MetadataExtractor.IO.ByteArrayReader.GetBytes(int index, System.Span bytes) -> void +override MetadataExtractor.IO.IndexedCapturingReader.GetBytes(int index, System.Span bytes) -> void +override MetadataExtractor.IO.IndexedSeekingReader.GetBytes(int index, System.Span bytes) -> void override MetadataExtractor.IO.SequentialByteArrayReader.GetBytes(System.Span bytes) -> void override MetadataExtractor.IO.SequentialStreamReader.GetBytes(System.Span bytes) -> void static MetadataExtractor.Formats.Apple.BplistReader.IsValid(byte[]! bplist) -> bool From 3143322dc07355b972a2d9ce648792fd8ed706a6 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Sat, 27 Jan 2024 23:24:11 +1100 Subject: [PATCH 2/2] Update API files and adjust diagnostic levels --- .editorconfig | 2 ++ MetadataExtractor/IO/IndexedReader.cs | 6 +++--- MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt | 7 ------- .../PublicAPI/net462/PublicAPI.Unshipped.txt | 8 +++++--- .../PublicAPI/netstandard1.3/PublicAPI.Shipped.txt | 7 ------- .../PublicAPI/netstandard2.1/PublicAPI.Shipped.txt | 7 ------- 6 files changed, 10 insertions(+), 27 deletions(-) diff --git a/.editorconfig b/.editorconfig index 563a979dd..4414d2a62 100644 --- a/.editorconfig +++ b/.editorconfig @@ -220,6 +220,8 @@ dotnet_diagnostic.CA1724.severity = suggestion # Type name co dotnet_diagnostic.CA1303.severity = none # Literal string should be localised dotnet_diagnostic.RS0016.severity = error # Symbol must be part of public API +dotnet_diagnostic.RS0017.severity = error # Symbol is part of the declared API, but could not be found +dotnet_diagnostic.RS0025.severity = error # Symbol appears more than once in the public API files # working around bug dotnet_diagnostic.RS0041.severity = none # Public members should not use oblivious types diff --git a/MetadataExtractor/IO/IndexedReader.cs b/MetadataExtractor/IO/IndexedReader.cs index ed610cbb0..1a8d91235 100644 --- a/MetadataExtractor/IO/IndexedReader.cs +++ b/MetadataExtractor/IO/IndexedReader.cs @@ -277,7 +277,7 @@ public float GetS15Fixed16(int index) /// public float GetFloat32(int index) { -#if NET45 || NETSTANDARD1_3 +#if NET462 || NETSTANDARD1_3 return BitConverter.ToSingle(BitConverter.GetBytes(GetInt32(index)), 0); #else Span bytes = stackalloc byte[4]; @@ -296,7 +296,7 @@ public float GetFloat32(int index) /// public double GetDouble64(int index) { -#if NET45 || NETSTANDARD1_3 +#if NET462 || NETSTANDARD1_3 return BitConverter.Int64BitsToDouble(GetInt64(index)); #else Span bytes = stackalloc byte[8]; @@ -315,7 +315,7 @@ public double GetDouble64(int index) /// public string GetString(int index, int bytesRequested, Encoding encoding) { -#if NET45 || NETSTANDARD1_3 +#if NET462 || NETSTANDARD1_3 var bytes = GetBytes(index, bytesRequested); return encoding.GetString(bytes, 0, bytes.Length); diff --git a/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt index 8285ef534..9a9812778 100644 --- a/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt +++ b/MetadataExtractor/PublicAPI/net462/PublicAPI.Shipped.txt @@ -12,8 +12,6 @@ abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.HasFollowerIfd() -> abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.ProcessTiffMarker(ushort marker) -> MetadataExtractor.Formats.Tiff.TiffStandard abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.TryCustomProcessFormat(int tagId, MetadataExtractor.Formats.Tiff.TiffDataFormatCode formatCode, ulong componentCount, out ulong byteCount) -> bool abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.TryEnterSubIfd(int tagType) -> bool -abstract MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]! -abstract MetadataExtractor.IO.IndexedReader.IsValidIndex(int index, int bytesRequested) -> bool abstract MetadataExtractor.IO.IndexedReader.Length.get -> long abstract MetadataExtractor.IO.IndexedReader.ToUnshiftedOffset(int localOffset) -> int abstract MetadataExtractor.IO.IndexedReader.ValidateIndex(int index, int bytesRequested) -> void @@ -4258,20 +4256,15 @@ override MetadataExtractor.Formats.Xmp.XmpDirectory.Name.get -> string! override MetadataExtractor.GeoLocation.Equals(object? obj) -> bool override MetadataExtractor.GeoLocation.GetHashCode() -> int override MetadataExtractor.GeoLocation.ToString() -> string! -override MetadataExtractor.IO.ByteArrayReader.GetBytes(int index, int count) -> byte[]! -override MetadataExtractor.IO.ByteArrayReader.IsValidIndex(int index, int bytesRequested) -> bool override MetadataExtractor.IO.ByteArrayReader.Length.get -> long override MetadataExtractor.IO.ByteArrayReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.ByteArrayReader.ValidateIndex(int index, int bytesRequested) -> void override MetadataExtractor.IO.ByteArrayReader.WithByteOrder(bool isMotorolaByteOrder) -> MetadataExtractor.IO.IndexedReader! override MetadataExtractor.IO.ByteArrayReader.WithShiftedBaseOffset(int shift) -> MetadataExtractor.IO.IndexedReader! -override MetadataExtractor.IO.IndexedCapturingReader.GetBytes(int index, int count) -> byte[]! override MetadataExtractor.IO.IndexedCapturingReader.Length.get -> long override MetadataExtractor.IO.IndexedCapturingReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.IndexedCapturingReader.WithByteOrder(bool isMotorolaByteOrder) -> MetadataExtractor.IO.IndexedReader! override MetadataExtractor.IO.IndexedCapturingReader.WithShiftedBaseOffset(int shift) -> MetadataExtractor.IO.IndexedReader! -override MetadataExtractor.IO.IndexedSeekingReader.GetBytes(int index, int count) -> byte[]! -override MetadataExtractor.IO.IndexedSeekingReader.IsValidIndex(int index, int bytesRequested) -> bool override MetadataExtractor.IO.IndexedSeekingReader.Length.get -> long override MetadataExtractor.IO.IndexedSeekingReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.IndexedSeekingReader.ValidateIndex(int index, int bytesRequested) -> void diff --git a/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt b/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt index bc8200c9b..a572972f7 100644 --- a/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt +++ b/MetadataExtractor/PublicAPI/net462/PublicAPI.Unshipped.txt @@ -1,5 +1,5 @@ #nullable enable -abstract MetadataExtractor.IO.IndexedReader.GetByteInternal(int index) -> byte +abstract MetadataExtractor.IO.IndexedReader.GetBytes(int index, System.Span bytes) -> void abstract MetadataExtractor.IO.SequentialReader.GetBytes(System.Span bytes) -> void const MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.TagEpoch = 2 -> int const MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.TagFlags = 1 -> int @@ -68,14 +68,16 @@ MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Descriptor.NikonPi MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory.NikonPictureControl2Directory() -> void MetadataExtractor.IO.IndexedReader.GetByte(int index) -> byte +MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]! override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDescriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.AppleRunTimeMakernoteDirectory.Name.get -> string! override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Descriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl1Directory.Name.get -> string! override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Descriptor.GetDescription(int tagType) -> string? override MetadataExtractor.Formats.Exif.Makernotes.NikonPictureControl2Directory.Name.get -> string! -override MetadataExtractor.IO.ByteArrayReader.GetByteInternal(int index) -> byte -override MetadataExtractor.IO.IndexedSeekingReader.GetByteInternal(int index) -> byte +override MetadataExtractor.IO.ByteArrayReader.GetBytes(int index, System.Span bytes) -> void +override MetadataExtractor.IO.IndexedCapturingReader.GetBytes(int index, System.Span bytes) -> void +override MetadataExtractor.IO.IndexedSeekingReader.GetBytes(int index, System.Span bytes) -> void override MetadataExtractor.IO.SequentialByteArrayReader.GetBytes(System.Span bytes) -> void override MetadataExtractor.IO.SequentialStreamReader.GetBytes(System.Span bytes) -> void static MetadataExtractor.Formats.Apple.BplistReader.IsValid(byte[]! bplist) -> bool diff --git a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt index b010a36b7..c84a0fabb 100644 --- a/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt +++ b/MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt @@ -12,8 +12,6 @@ abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.HasFollowerIfd() -> abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.ProcessTiffMarker(ushort marker) -> MetadataExtractor.Formats.Tiff.TiffStandard abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.TryCustomProcessFormat(int tagId, MetadataExtractor.Formats.Tiff.TiffDataFormatCode formatCode, ulong componentCount, out ulong byteCount) -> bool abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.TryEnterSubIfd(int tagType) -> bool -abstract MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]! -abstract MetadataExtractor.IO.IndexedReader.IsValidIndex(int index, int bytesRequested) -> bool abstract MetadataExtractor.IO.IndexedReader.Length.get -> long abstract MetadataExtractor.IO.IndexedReader.ToUnshiftedOffset(int localOffset) -> int abstract MetadataExtractor.IO.IndexedReader.ValidateIndex(int index, int bytesRequested) -> void @@ -4251,20 +4249,15 @@ override MetadataExtractor.Formats.Xmp.XmpDirectory.Name.get -> string! override MetadataExtractor.GeoLocation.Equals(object? obj) -> bool override MetadataExtractor.GeoLocation.GetHashCode() -> int override MetadataExtractor.GeoLocation.ToString() -> string! -override MetadataExtractor.IO.ByteArrayReader.GetBytes(int index, int count) -> byte[]! -override MetadataExtractor.IO.ByteArrayReader.IsValidIndex(int index, int bytesRequested) -> bool override MetadataExtractor.IO.ByteArrayReader.Length.get -> long override MetadataExtractor.IO.ByteArrayReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.ByteArrayReader.ValidateIndex(int index, int bytesRequested) -> void override MetadataExtractor.IO.ByteArrayReader.WithByteOrder(bool isMotorolaByteOrder) -> MetadataExtractor.IO.IndexedReader! override MetadataExtractor.IO.ByteArrayReader.WithShiftedBaseOffset(int shift) -> MetadataExtractor.IO.IndexedReader! -override MetadataExtractor.IO.IndexedCapturingReader.GetBytes(int index, int count) -> byte[]! override MetadataExtractor.IO.IndexedCapturingReader.Length.get -> long override MetadataExtractor.IO.IndexedCapturingReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.IndexedCapturingReader.WithByteOrder(bool isMotorolaByteOrder) -> MetadataExtractor.IO.IndexedReader! override MetadataExtractor.IO.IndexedCapturingReader.WithShiftedBaseOffset(int shift) -> MetadataExtractor.IO.IndexedReader! -override MetadataExtractor.IO.IndexedSeekingReader.GetBytes(int index, int count) -> byte[]! -override MetadataExtractor.IO.IndexedSeekingReader.IsValidIndex(int index, int bytesRequested) -> bool override MetadataExtractor.IO.IndexedSeekingReader.Length.get -> long override MetadataExtractor.IO.IndexedSeekingReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.IndexedSeekingReader.ValidateIndex(int index, int bytesRequested) -> void diff --git a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt index 3325324f4..f48d8a0e9 100644 --- a/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt +++ b/MetadataExtractor/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt @@ -12,8 +12,6 @@ abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.HasFollowerIfd() -> abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.ProcessTiffMarker(ushort marker) -> MetadataExtractor.Formats.Tiff.TiffStandard abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.TryCustomProcessFormat(int tagId, MetadataExtractor.Formats.Tiff.TiffDataFormatCode formatCode, ulong componentCount, out ulong byteCount) -> bool abstract MetadataExtractor.Formats.Tiff.DirectoryTiffHandler.TryEnterSubIfd(int tagType) -> bool -abstract MetadataExtractor.IO.IndexedReader.GetBytes(int index, int count) -> byte[]! -abstract MetadataExtractor.IO.IndexedReader.IsValidIndex(int index, int bytesRequested) -> bool abstract MetadataExtractor.IO.IndexedReader.Length.get -> long abstract MetadataExtractor.IO.IndexedReader.ToUnshiftedOffset(int localOffset) -> int abstract MetadataExtractor.IO.IndexedReader.ValidateIndex(int index, int bytesRequested) -> void @@ -4253,20 +4251,15 @@ override MetadataExtractor.Formats.Xmp.XmpDirectory.Name.get -> string! override MetadataExtractor.GeoLocation.Equals(object? obj) -> bool override MetadataExtractor.GeoLocation.GetHashCode() -> int override MetadataExtractor.GeoLocation.ToString() -> string! -override MetadataExtractor.IO.ByteArrayReader.GetBytes(int index, int count) -> byte[]! -override MetadataExtractor.IO.ByteArrayReader.IsValidIndex(int index, int bytesRequested) -> bool override MetadataExtractor.IO.ByteArrayReader.Length.get -> long override MetadataExtractor.IO.ByteArrayReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.ByteArrayReader.ValidateIndex(int index, int bytesRequested) -> void override MetadataExtractor.IO.ByteArrayReader.WithByteOrder(bool isMotorolaByteOrder) -> MetadataExtractor.IO.IndexedReader! override MetadataExtractor.IO.ByteArrayReader.WithShiftedBaseOffset(int shift) -> MetadataExtractor.IO.IndexedReader! -override MetadataExtractor.IO.IndexedCapturingReader.GetBytes(int index, int count) -> byte[]! override MetadataExtractor.IO.IndexedCapturingReader.Length.get -> long override MetadataExtractor.IO.IndexedCapturingReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.IndexedCapturingReader.WithByteOrder(bool isMotorolaByteOrder) -> MetadataExtractor.IO.IndexedReader! override MetadataExtractor.IO.IndexedCapturingReader.WithShiftedBaseOffset(int shift) -> MetadataExtractor.IO.IndexedReader! -override MetadataExtractor.IO.IndexedSeekingReader.GetBytes(int index, int count) -> byte[]! -override MetadataExtractor.IO.IndexedSeekingReader.IsValidIndex(int index, int bytesRequested) -> bool override MetadataExtractor.IO.IndexedSeekingReader.Length.get -> long override MetadataExtractor.IO.IndexedSeekingReader.ToUnshiftedOffset(int localOffset) -> int override MetadataExtractor.IO.IndexedSeekingReader.ValidateIndex(int index, int bytesRequested) -> void