///////////////////////////////////////////////////////////////////////////////// // // Photoshop PSD FileType Plugin for Paint.NET // http://psdplugin.codeplex.com/ // // This software is provided under the MIT License: // Copyright (c) 2006-2007 Frank Blumenberg // Copyright (c) 2010-2019 Tao Yue // // Portions of this file are provided under the BSD 3-clause License: // Copyright (c) 2006, Jonas Beckeman // // See LICENSE.txt for complete licensing and attribution information. // ///////////////////////////////////////////////////////////////////////////////// using System; using System.Diagnostics; using System.IO; namespace PhotoshopFile { public class RleReader { private Stream stream; public RleReader(Stream stream) { this.stream = stream; } /// /// Decodes a PackBits RLE stream. /// /// Output buffer for decoded data. /// Offset at which to begin writing. /// Number of bytes to decode from the stream. unsafe public int Read(byte[] buffer, int offset, int count) { if (!Util.CheckBufferBounds(buffer, offset, count)) { throw new ArgumentOutOfRangeException(); } if (count == 0) { return 0; } // Pin the entire buffer now, so that we don't keep pinning and unpinning // for each RLE packet. fixed (byte* ptrBuffer = &buffer[0]) { int bytesLeft = count; int bufferIdx = offset; while (bytesLeft > 0) { // ReadByte returns an unsigned byte, but we want a signed byte. var flagCounter = unchecked((sbyte)stream.ReadByte()); // Raw packet if (flagCounter > 0) { var readLength = flagCounter + 1; if (bytesLeft < readLength) throw new RleException("Raw packet overruns the decode window."); stream.Read(buffer, bufferIdx, readLength); bufferIdx += readLength; bytesLeft -= readLength; } // RLE packet else if (flagCounter > -128) { var runLength = 1 - flagCounter; var byteValue = (byte)stream.ReadByte(); if (runLength > bytesLeft) throw new RleException("RLE packet overruns the decode window."); byte* ptr = ptrBuffer + bufferIdx; byte* ptrEnd = ptr + runLength; while (ptr < ptrEnd) { *ptr = byteValue; ptr++; } bufferIdx += runLength; bytesLeft -= runLength; } else { // The canonical PackBits algorithm will never emit 0x80 (-128), but // some programs do. Simply skip over the byte. } } Debug.Assert(bytesLeft == 0); return count - bytesLeft; } } } }