public void BufferedStreamCanSkip(int bufferSize) { this.configuration.StreamProcessingBufferSize = bufferSize; using (MemoryStream stream = this.CreateTestStream(bufferSize * 4)) { byte[] expected = stream.ToArray(); using (var reader = new BufferedReadStream(this.configuration, stream)) { int skip = 1; int plusOne = 1; int skip2 = bufferSize; // Skip reader.Skip(skip); Assert.Equal(skip, reader.Position); Assert.Equal(stream.Position, reader.Position); // Read Assert.Equal(expected[skip], reader.ReadByte()); // Skip Again reader.Skip(skip2); // First Skip + First Read + Second Skip int position = skip + plusOne + skip2; Assert.Equal(position, reader.Position); Assert.Equal(stream.Position, reader.Position); Assert.Equal(expected[position], reader.ReadByte()); } } }
public void BufferedStreamCanSkip() { using (MemoryStream stream = this.CreateTestStream()) { byte[] expected = stream.ToArray(); using (var reader = new BufferedReadStream(stream)) { int skip = 50; int plusOne = 1; int skip2 = BufferedReadStream.BufferLength; // Skip reader.Skip(skip); Assert.Equal(skip, reader.Position); Assert.Equal(stream.Position, reader.Position); // Read Assert.Equal(expected[skip], reader.ReadByte()); // Skip Again reader.Skip(skip2); // First Skip + First Read + Second Skip int position = skip + plusOne + skip2; Assert.Equal(position, reader.Position); Assert.Equal(stream.Position, reader.Position); Assert.Equal(expected[position], reader.ReadByte()); } } }
/// <summary> /// Parses the input stream for file markers. /// </summary> /// <param name="stream">The input stream.</param> /// <param name="scanDecoder">Scan decoder used exclusively to decode SOS marker.</param> /// <param name="cancellationToken">The token to monitor cancellation.</param> internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDecoder, CancellationToken cancellationToken) { bool metadataOnly = scanDecoder == null; this.scanDecoder = scanDecoder; this.Metadata = new ImageMetadata(); // Check for the Start Of Image marker. stream.Read(this.markerBuffer, 0, 2); var fileMarker = new JpegFileMarker(this.markerBuffer[1], 0); if (fileMarker.Marker != JpegConstants.Markers.SOI) { JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker."); } stream.Read(this.markerBuffer, 0, 2); byte marker = this.markerBuffer[1]; fileMarker = new JpegFileMarker(marker, (int)stream.Position - 2); this.QuantizationTables ??= new Block8x8F[4]; // Break only when we discover a valid EOI marker. // https://github.com/SixLabors/ImageSharp/issues/695 while (fileMarker.Marker != JpegConstants.Markers.EOI || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid)) { cancellationToken.ThrowIfCancellationRequested(); if (!fileMarker.Invalid) { // Get the marker length. int remaining = this.ReadUint16(stream) - 2; switch (fileMarker.Marker) { case JpegConstants.Markers.SOF0: case JpegConstants.Markers.SOF1: case JpegConstants.Markers.SOF2: this.ProcessStartOfFrameMarker(stream, remaining, fileMarker, metadataOnly); break; case JpegConstants.Markers.SOF5: JpegThrowHelper.ThrowNotSupportedException("Decoding jpeg files with differential sequential DCT is not supported."); break; case JpegConstants.Markers.SOF6: JpegThrowHelper.ThrowNotSupportedException("Decoding jpeg files with differential progressive DCT is not supported."); break; case JpegConstants.Markers.SOF3: case JpegConstants.Markers.SOF7: JpegThrowHelper.ThrowNotSupportedException("Decoding lossless jpeg files is not supported."); break; case JpegConstants.Markers.SOF9: case JpegConstants.Markers.SOF10: case JpegConstants.Markers.SOF11: case JpegConstants.Markers.SOF13: case JpegConstants.Markers.SOF14: case JpegConstants.Markers.SOF15: JpegThrowHelper.ThrowNotSupportedException("Decoding jpeg files with arithmetic coding is not supported."); break; case JpegConstants.Markers.SOS: if (!metadataOnly) { this.ProcessStartOfScanMarker(stream, remaining); break; } else { // It's highly unlikely that APPn related data will be found after the SOS marker // We should have gathered everything we need by now. return; } case JpegConstants.Markers.DHT: if (metadataOnly) { stream.Skip(remaining); } else { this.ProcessDefineHuffmanTablesMarker(stream, remaining); } break; case JpegConstants.Markers.DQT: this.ProcessDefineQuantizationTablesMarker(stream, remaining); break; case JpegConstants.Markers.DRI: if (metadataOnly) { stream.Skip(remaining); } else { this.ProcessDefineRestartIntervalMarker(stream, remaining); } break; case JpegConstants.Markers.APP0: this.ProcessApplicationHeaderMarker(stream, remaining); break; case JpegConstants.Markers.APP1: this.ProcessApp1Marker(stream, remaining); break; case JpegConstants.Markers.APP2: this.ProcessApp2Marker(stream, remaining); break; case JpegConstants.Markers.APP3: case JpegConstants.Markers.APP4: case JpegConstants.Markers.APP5: case JpegConstants.Markers.APP6: case JpegConstants.Markers.APP7: case JpegConstants.Markers.APP8: case JpegConstants.Markers.APP9: case JpegConstants.Markers.APP10: case JpegConstants.Markers.APP11: case JpegConstants.Markers.APP12: stream.Skip(remaining); break; case JpegConstants.Markers.APP13: this.ProcessApp13Marker(stream, remaining); break; case JpegConstants.Markers.APP14: this.ProcessApp14Marker(stream, remaining); break; case JpegConstants.Markers.APP15: case JpegConstants.Markers.COM: stream.Skip(remaining); break; case JpegConstants.Markers.DAC: JpegThrowHelper.ThrowNotSupportedException("Decoding jpeg files with arithmetic coding is not supported."); break; } } // Read on. fileMarker = FindNextFileMarker(this.markerBuffer, stream); } }
/// <summary> /// Parses the input stream for file markers /// </summary> /// <param name="stream">The input stream</param> /// <param name="metadataOnly">Whether to decode metadata only.</param> /// <param name="cancellationToken">The token to monitor cancellation.</param> public void ParseStream(BufferedReadStream stream, bool metadataOnly = false, CancellationToken cancellationToken = default) { this.Metadata = new ImageMetadata(); // Check for the Start Of Image marker. stream.Read(this.markerBuffer, 0, 2); var fileMarker = new JpegFileMarker(this.markerBuffer[1], 0); if (fileMarker.Marker != JpegConstants.Markers.SOI) { JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker."); } stream.Read(this.markerBuffer, 0, 2); byte marker = this.markerBuffer[1]; fileMarker = new JpegFileMarker(marker, (int)stream.Position - 2); this.QuantizationTables = new Block8x8F[4]; // Only assign what we need if (!metadataOnly) { const int maxTables = 4; this.dcHuffmanTables = new HuffmanTable[maxTables]; this.acHuffmanTables = new HuffmanTable[maxTables]; } // Break only when we discover a valid EOI marker. // https://github.com/SixLabors/ImageSharp/issues/695 while (fileMarker.Marker != JpegConstants.Markers.EOI || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid)) { cancellationToken.ThrowIfCancellationRequested(); if (!fileMarker.Invalid) { // Get the marker length int remaining = this.ReadUint16(stream) - 2; switch (fileMarker.Marker) { case JpegConstants.Markers.SOF0: case JpegConstants.Markers.SOF1: case JpegConstants.Markers.SOF2: this.ProcessStartOfFrameMarker(stream, remaining, fileMarker, metadataOnly); break; case JpegConstants.Markers.SOS: if (!metadataOnly) { this.ProcessStartOfScanMarker(stream, cancellationToken); break; } else { // It's highly unlikely that APPn related data will be found after the SOS marker // We should have gathered everything we need by now. return; } case JpegConstants.Markers.DHT: if (metadataOnly) { stream.Skip(remaining); } else { this.ProcessDefineHuffmanTablesMarker(stream, remaining); } break; case JpegConstants.Markers.DQT: this.ProcessDefineQuantizationTablesMarker(stream, remaining); break; case JpegConstants.Markers.DRI: if (metadataOnly) { stream.Skip(remaining); } else { this.ProcessDefineRestartIntervalMarker(stream, remaining); } break; case JpegConstants.Markers.APP0: this.ProcessApplicationHeaderMarker(stream, remaining); break; case JpegConstants.Markers.APP1: this.ProcessApp1Marker(stream, remaining); break; case JpegConstants.Markers.APP2: this.ProcessApp2Marker(stream, remaining); break; case JpegConstants.Markers.APP3: case JpegConstants.Markers.APP4: case JpegConstants.Markers.APP5: case JpegConstants.Markers.APP6: case JpegConstants.Markers.APP7: case JpegConstants.Markers.APP8: case JpegConstants.Markers.APP9: case JpegConstants.Markers.APP10: case JpegConstants.Markers.APP11: case JpegConstants.Markers.APP12: stream.Skip(remaining); break; case JpegConstants.Markers.APP13: this.ProcessApp13Marker(stream, remaining); break; case JpegConstants.Markers.APP14: this.ProcessApp14Marker(stream, remaining); break; case JpegConstants.Markers.APP15: case JpegConstants.Markers.COM: stream.Skip(remaining); break; } } // Read on. fileMarker = FindNextFileMarker(this.markerBuffer, stream); } }