Ejemplo n.º 1
0
        public async Task <byte[]> ParseRectangle(PipeReader reader, RfbRectangleHeader header, PixelFormat format, CancellationToken token)
        {
            Debug.Assert(format.BitsPerPixel == 32);
            var ZRLEPipe = new Pipe();
            var parser   = Task.Run(() => ParsePixelData(ZRLEPipe.Reader, header, token));

            // read compressed length
            var result = await reader.ReadMinBytesAsync(4, token);

            var length = BinaryPrimitives.ReadUInt32BigEndian(result.Buffer.ForceGetReadOnlySpan(4));

            reader.AdvanceTo(result.Buffer.GetPosition(4));
            long remaining = length;

            if (Fresh)
            {
                result = await reader.ReadMinBytesAsync(2, token);

                reader.AdvanceTo(result.Buffer.GetPosition(2));
                remaining -= 2;
                Fresh      = false;
            }

            // handle compressed rect
            while (remaining > 0)
            {
                result = await reader.ReadAsync();

                long decompressed = 0;
                foreach (var segment in result.Buffer)
                {
                    if (remaining > segment.Length)
                    {
                        await Decompress(ZRLEPipe.Writer, segment);

                        decompressed += segment.Length;
                        remaining    -= segment.Length;
                    }
                    else
                    {
                        await Decompress(ZRLEPipe.Writer, segment.Slice(0, (int)remaining));

                        decompressed += remaining;
                        remaining    -= remaining;
                        break;
                    }
                }
                reader.AdvanceTo(result.Buffer.GetPosition(decompressed));
                if (remaining > 0 && result.IsCompleted)
                {
                    throw new VncConnectionException();
                }
            }
            ZRLEPipe.Writer.Complete();
            return(await parser);
        }
Ejemplo n.º 2
0
        public async Task <byte[]> ParseRectangle(PipeReader reader, RfbRectangleHeader header, PixelFormat format, CancellationToken token)
        {
            Debug.Assert(format.BitsPerPixel == 32);
            var remainingPixels = header.Width * header.Height;
            var buf             = ArrayPool <byte> .Shared.Rent(remainingPixels * 4);

            var destPos = 0;

            while (remainingPixels > 0)
            {
                var result = await reader.ReadAsync(token);

                byte[]? remainder = null;
                int read = 0;
                foreach (var segment in result.Buffer)
                {
                    if (remainingPixels == 0)
                    {
                        break;
                    }
                    int s = 0;
                    if (remainder != null)
                    {
                        if (remainder.Length + segment.Length < 4) // segment + remainder not big enough
                        {
                            var newRemainder = new byte[remainder.Length + segment.Length];
                            remainder.CopyTo(newRemainder, 0);
                            segment.CopyTo(newRemainder.AsMemory(remainder.Length));
                            continue;
                        }
                        else // segment + remainder big enough
                        {
                            var completedReminder = new byte[4];
                            remainder.CopyTo(completedReminder, 0);
                            segment.Span.Slice(0, 3 - remainder.Length).CopyTo(completedReminder.AsSpan(remainder.Length));
                            completedReminder.CopyTo(buf, destPos);
                            buf[destPos + 3] = 0xff;
                            remainingPixels--;
                            read     += 4;
                            destPos  += 4;
                            s         = 4 - remainder.Length;
                            remainder = null;
                        }
                    }
                    while (remainingPixels > 0)
                    {
                        if (s + 4 <= segment.Length) // segment big enough
                        {
                            segment.Slice(s, 3).CopyTo(buf.AsMemory(destPos));
                            buf[destPos + 3] = 0xff;
                            remainingPixels--;
                            read    += 4;
                            destPos += 4;
                            s       += 4;
                        }
                        else if (s + 4 > segment.Length) // segment not big enough
                        {
                            remainder = segment.Slice(s).ToArray();
                            break;
                        }
                    }
                }
                reader.AdvanceTo(result.Buffer.GetPosition(read));
                if (remainingPixels > 0 && result.IsCompleted)
                {
                    throw new VncConnectionException();
                }
            }
            return(buf);
        }
Ejemplo n.º 3
0
        private async Task <byte[]> ParsePixelData(PipeReader uncompressedReader, RfbRectangleHeader header, CancellationToken token)
        {
            byte[] data = ArrayPool <byte> .Shared.Rent(header.Width *header.Height * 4);

            Array.Clear(data, 0, data.Length);
            for (var y = 0; y < header.Height; y += 64)
            {
                var tileHeight = Math.Min(header.Height - y, 64);
                for (var x = 0; x < header.Width; x += 64)
                {
                    var tileWidth = Math.Min(header.Width - x, 64);
                    var result    = await uncompressedReader.ReadMinBytesAsync(1, token);

                    byte subencoding = result.Buffer.First.Span[0];
                    uncompressedReader.AdvanceTo(result.Buffer.GetPosition(1));
                    //Debug.WriteLine($"subencoding {subencoding}");

                    if (subencoding == 0) // Raw
                    {
                        await ParseRawTile(uncompressedReader, data, x, y, tileWidth, tileHeight, header.Width);
                    }
                    else if (subencoding == 1) // Solid
                    {
                        var pixel = await ParseCompressedPixel(uncompressedReader, token);

                        for (int ty = 0; ty < tileHeight; ty++)
                        {
                            for (int tx = 0; tx < tileWidth; tx++)
                            {
                                Buffer.BlockCopy(pixel, 0, data, (
                                                     ((y + ty) * header.Width) + // y + ty rows
                                                     (x + tx)                    // x + tx colums
                                                     ) * 4, 4);                  // 4 bytes per pixel
                            }
                        }
                        ArrayPool <byte> .Shared.Return(pixel);
                    }
                    else if (subencoding <= 16) // Packed Palette
                    {
                        await ParsePackedPaletteTile(uncompressedReader, data, x, y, tileWidth, tileHeight, header.Width, subencoding);
                    }
                    else if (17 <= subencoding && subencoding <= 127)
                    {
                        throw new InvalidDataException("Subencodings 17 to 127 are unused");
                    }
                    else if (subencoding == 128) // Plain RLE
                    {
                        await ParsePlainRLETile(uncompressedReader, data, x, y, tileWidth, tileHeight, header.Width);
                    }
                    else if (130 <= subencoding && subencoding <= 255) // Palette RLE
                    {
                        await ParsePaletteRLETile(uncompressedReader, data, x, y, tileWidth, tileHeight, header.Width, subencoding - 128);
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
            }
            return(data);
        }