private bool valid; // if voidStar is null, and this is false, we know that it's null because allocation failed. otherwise we have a real error

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Creates a new MemoryBlock instance and allocates the requested number of bytes.
        /// </summary>
        /// <param name="bytes"></param>
        public MemoryBlock(long bytes)
        {
            if (bytes <= 0)
            {
                throw new ArgumentOutOfRangeException("bytes", bytes, "Bytes must be greater than zero");
            }

            this.length = bytes;
            this.parentBlock = null;
            this.voidStar = Allocate(bytes).ToPointer();
            this.valid = true;
        }
        /// <summary>
        /// Creates a new instance of the Surface class.
        /// </summary>
        /// <param name="width">The width, in pixels, of the new Surface.</param>
        /// <param name="height">The height, in pixels, of the new Surface.</param>
        public Surface(int width, int height)
        {
            int stride;
            long bytes;

            try
            {
                stride = checked(width * ColorBgra.SizeOf);
                bytes = (long)height * (long)stride;
            }

            catch (OverflowException ex)
            {
                throw new OutOfMemoryException("Dimensions are too large - not enough memory, width=" + width.ToString() + ", height=" + height.ToString(), ex);
            }

            MemoryBlock scan0 = new MemoryBlock(width, height);
            Create(width, height, stride, scan0);
        }
        public MemoryBlock(int width, int height)
        {
            if (width < 0 && height < 0)
            {
                throw new ArgumentOutOfRangeException("width/height", new Size(width, height), "width and height must be >= 0");
            }
            else if (width < 0)
            {
                throw new ArgumentOutOfRangeException("width", width, "width must be >= 0");
            }
            else if (height < 0)
            {
                throw new ArgumentOutOfRangeException("height", width, "height must be >= 0");
            }

            this.length = width * height * ColorBgra.SizeOf;
            this.parentBlock = null;
            this.voidStar = Allocate(width, height, out this.bitmapHandle).ToPointer();
            this.valid = true;
            this.bitmapWidth = width;
            this.bitmapHeight = height;
        }
        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                disposed = true;

                if (disposing)
                {
                }

                if (this.valid && parentBlock == null)
                {
                    if (this.bitmapHandle != IntPtr.Zero)
                    {
                        Memory.FreeBitmap(this.bitmapHandle, this.bitmapWidth, this.bitmapHeight);
                    }
                    else if (this.length >= largeBlockThreshold)
                    {
                        Memory.FreeLarge(new IntPtr(voidStar), (ulong)this.length);
                    }
                    else
                    {
                        Memory.Free(new IntPtr(voidStar));
                    }
                }

                parentBlock = null;
                Memory.Free((IntPtr)voidStar);
                voidStar = null;
                this.valid = false;
            }
        }
        /// <summary>
        /// Creates a new parent MemoryBlock and copies our contents into it
        /// </summary>
        public MemoryBlock Clone()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("MemoryBlock");
            }

            MemoryBlock dupe = new MemoryBlock(this.length);
            CopyBlock(dupe, 0, this, 0, length);
            return dupe;
        }
        /// <summary>
        /// Copies bytes from one area of memory to another. Since this function works
        /// with MemoryBlock instances, it does bounds checking.
        /// </summary>
        /// <param name="dst">The MemoryBlock to copy bytes to.</param>
        /// <param name="dstOffset">The offset within dst to copy bytes to.</param>
        /// <param name="src">The MemoryBlock to copy bytes from.</param>
        /// <param name="srcOffset">The offset within src to copy bytes from.</param>
        /// <param name="length">The number of bytes to copy.</param>
        public static void CopyBlock(MemoryBlock dst, long dstOffset, MemoryBlock src, long srcOffset, long length)
        {
            if ((dstOffset + length > dst.length) || (srcOffset + length > src.length))
            {
                throw new ArgumentOutOfRangeException("", "copy ranges were out of bounds");
            }

            if (dstOffset < 0)
            {
                throw new ArgumentOutOfRangeException("dstOffset", dstOffset, "must be >= 0");
            }

            if (srcOffset < 0)
            {
                throw new ArgumentOutOfRangeException("srcOffset", srcOffset, "must be >= 0");
            }

            if (length < 0)
            {
                throw new ArgumentOutOfRangeException("length", length, "must be >= 0");
            }

            void *dstPtr = (void *)((byte *)dst.VoidStar + dstOffset);
            void *srcPtr = (void *)((byte *)src.VoidStar + srcOffset);
            Memory.Copy(dstPtr, srcPtr, (ulong)length);
        }
        /// <summary>
        /// Creates a new MemoryBlock instance that refers to part of another MemoryBlock.
        /// The other MemoryBlock is the parent, and this new instance is the child.
        /// </summary>
        public unsafe MemoryBlock(MemoryBlock parentBlock, long offset, long length)
        {
            if (offset + length > parentBlock.length)
            {
                throw new ArgumentOutOfRangeException();
            }

            this.parentBlock = parentBlock;
            byte *bytePointer = (byte *)parentBlock.VoidStar;
            bytePointer += offset;
            this.voidStar = (void *)bytePointer;
            this.valid = true;
            this.length = length;
        }
Exemple #8
0
 private void ExpandUncompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, int xoffset, ColorBgra[] palette)
 {
     for (int i = 0; i < width; ++i)
     {
         ColorBgra color = ReadColor(input, header.pixelDepth, palette);
         dst[dstIndex] = color[0];
         dst[1 + dstIndex] = color[1];
         dst[2 + dstIndex] = color[2];
         dst[3 + dstIndex] = color[3];
         dstIndex += 4;
     }
 }
Exemple #9
0
        private byte ExpandCompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, byte rleLeftOver, ColorBgra[] palette)
        {
            byte rle;
            long filePos = 0;

            int x = 0;
            while (x < width)
            {
                if (rleLeftOver != 255)
                {
                    rle = rleLeftOver;
                    rleLeftOver = 255;
                }
                else
                {
                    int byte1 = input.ReadByte();

                    if (byte1 == -1)
                    {
                        throw new EndOfStreamException();
                    }
                    else
                    {
                        rle = (byte)byte1;
                    }
                }

                if ((rle & 128) != 0)
                {
                    // RLE Encoded packet
                    rle -= 127; // calculate real repeat count

                    if ((x + rle) > width)
                    {
                        rleLeftOver = (byte)(128 + (rle - (width - x) - 1));
                        filePos = input.Position;
                        rle = (byte)(width - x);
                    }
                
                    ColorBgra color = ReadColor(input, header.pixelDepth, palette);

                    for (int ix = 0; ix < rle; ++ix)
                    {
                        int index = dstIndex + (ix * ColorBgra.SizeOf);

                        dst[index] = color[0];
                        dst[1 + index] = color[1];
                        dst[2 + index] = color[2];
                        dst[3 + index] = color[3];
                    }

                    if (rleLeftOver != 255)
                    {
                        input.Position = filePos;
                    }
                }
                else
                {
                    // Raw packet
                    rle += 1; // calculate real repeat count

                    if ((x + rle) > width)
                    {
                        rleLeftOver = (byte)(rle - (width - x) - 1);
                        rle = (byte)(width - x);
                    }

                    ExpandUncompressedLine(dst, dstIndex, ref header, input, rle, y, x, palette);
                }

                dstIndex += rle * ColorBgra.SizeOf;
                x += rle;
            }

            return rleLeftOver;
        }
Exemple #10
0
        private MemoryBlock(SerializationInfo info, StreamingContext context)
        {
            disposed = false;

            // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value.
            try
            {
                 this.length = info.GetInt64("length64");
            }

            catch (SerializationException)
            {
                this.length = (long)info.GetInt32("length");
            }

            try
            {
                this.bitmapWidth = (int)info.GetInt32("bitmapWidth");
                this.bitmapHeight = (int)info.GetInt32("bitmapHeight");

                if (this.bitmapWidth != 0 || this.bitmapHeight != 0)
                {
                    long bytes = (long)this.bitmapWidth * (long)this.bitmapHeight * (long)ColorBgra.SizeOf;

                    if (bytes != this.length)
                    {
                        throw new ApplicationException("Invalid file format: width * height * 4 != length");
                    }
                }
            }

            catch (SerializationException)
            {
                this.bitmapWidth = 0;
                this.bitmapHeight = 0;
            }

            bool hasParent = info.GetBoolean("hasParent");

            if (hasParent)
            {
                this.parentBlock = (MemoryBlock)info.GetValue("parentBlock", typeof(MemoryBlock));

                // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value.
                long parentOffset;

                try
                {
                    parentOffset = info.GetInt64("parentOffset64");
                }

                catch (SerializationException)
                {
                    parentOffset = (long)info.GetInt32("parentOffset");
                }

                this.voidStar = (void *)((byte *)parentBlock.VoidStar + parentOffset);
                this.valid = true;
            }
            else
            {
                DeferredFormatter deferredFormatter = context.Context as DeferredFormatter;
                bool deferred = false;

                // Was this stream serialized with deferment?
                foreach (SerializationEntry entry in info)
                {
                    if (entry.Name == "deferred")
                    {
                        deferred = (bool)entry.Value;
                        break;
                    }
                }

                if (deferred && deferredFormatter != null)
                {
                    // The newest PDN files use deferred deserialization. This lets us read straight from the stream,
                    // minimizing memory use and adding the potential for multithreading
                    // Deserialization will complete in IDeferredDeserializer.FinishDeserialization()
                    deferredFormatter.AddDeferredObject(this, this.length);
                }
                else if (deferred && deferredFormatter == null)
                {
                    throw new InvalidOperationException("stream has deferred serialization streams, but a DeferredFormatter was not provided");
                }
                else
                {
                    this.voidStar = Allocate(this.length).ToPointer();
                    this.valid = true;

                    // Non-deferred format serializes one big byte[] chunk. This is also
                    // how PDN files were saved with v2.1 Beta 2 and before.
                    byte[] array = (byte[])info.GetValue("pointerData", typeof(byte[]));

                    fixed (byte *pbArray = array)
                    {
                        Memory.Copy(this.VoidStar, (void *)pbArray, (ulong)array.LongLength);
                    }
                }
            }
        }
 /// <summary>
 /// Creates a new instance of the Surface class that reuses a block of memory that was previously allocated.
 /// </summary>
 /// <param name="width">The width, in pixels, for the Surface.</param>
 /// <param name="height">The height, in pixels, for the Surface.</param>
 /// <param name="stride">The stride, in bytes, for the Surface.</param>
 /// <param name="scan0">The MemoryBlock to use. The beginning of this buffer defines the upper left (0, 0) pixel of the Surface.</param>
 private Surface(int width, int height, int stride, MemoryBlock scan0)
 {
     Create(width, height, stride, scan0);
 }
        private MemoryBlock GetRootMemoryBlock(MemoryBlock block)
        {
            MemoryBlock p = block;

            while (p.Parent != null)
            {
                p = p.Parent;
            }

            return p;
        }
        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                disposed = true;

                if (disposing)
                {
                    scan0.Dispose();
                    scan0 = null;
                }
            }
        }
 private void Create(int width, int height, int stride, MemoryBlock scan0)
 {
     this.width = width;
     this.height = height;
     this.stride = stride;
     this.scan0 = scan0;
 }
        public Surface CreateWindow(int x, int y, int windowWidth, int windowHeight)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("Surface");
            }

            if (windowHeight == 0)
            {
                throw new ArgumentOutOfRangeException("windowHeight", "must be greater than zero");
            }

            Rectangle original = this.Bounds;
            Rectangle sub = new Rectangle(x, y, windowWidth, windowHeight);
            Rectangle clipped = Rectangle.Intersect(original, sub);

            if (clipped != sub)
            {
                throw new ArgumentOutOfRangeException("bounds", new Rectangle(x, y, windowWidth, windowHeight),
                    "bounds parameters must be a subset of this Surface's bounds");
            }

            long offset = ((long)stride * (long)y) + ((long)ColorBgra.SizeOf * (long)x);
            long length = ((windowHeight - 1) * (long)stride) + (long)windowWidth * (long)ColorBgra.SizeOf;
            MemoryBlock block = new MemoryBlock(this.scan0, offset, length);
            return new Surface(windowWidth, windowHeight, this.stride, block);
        }
        private MemoryBlock(SerializationInfo info, StreamingContext context)
        {
            disposed = false;

            // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value.
            try {
                this.length = info.GetInt64("length64");
            } catch (SerializationException) {
                this.length = (long)info.GetInt32("length");
            }

            try {
                this.bitmapWidth  = (int)info.GetInt32("bitmapWidth");
                this.bitmapHeight = (int)info.GetInt32("bitmapHeight");

                if (this.bitmapWidth != 0 || this.bitmapHeight != 0)
                {
                    long bytes = (long)this.bitmapWidth * (long)this.bitmapHeight * (long)ColorBgra.SizeOf;

                    if (bytes != this.length)
                    {
                        throw new ApplicationException("Invalid file format: width * height * 4 != length");
                    }
                }
            } catch (SerializationException) {
                this.bitmapWidth  = 0;
                this.bitmapHeight = 0;
            }

            bool hasParent = info.GetBoolean("hasParent");

            if (hasParent)
            {
                this.parentBlock = (MemoryBlock)info.GetValue("parentBlock", typeof(MemoryBlock));

                // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value.
                long parentOffset;

                try {
                    parentOffset = info.GetInt64("parentOffset64");
                } catch (SerializationException) {
                    parentOffset = (long)info.GetInt32("parentOffset");
                }

                this.voidStar = (void *)((byte *)parentBlock.VoidStar + parentOffset);
                this.valid    = true;
            }
            else
            {
                DeferredFormatter deferredFormatter = context.Context as DeferredFormatter;
                bool deferred = false;

                // Was this stream serialized with deferment?
                foreach (SerializationEntry entry in info)
                {
                    if (entry.Name == "deferred")
                    {
                        deferred = (bool)entry.Value;
                        break;
                    }
                }

                if (deferred && deferredFormatter != null)
                {
                    // The newest PDN files use deferred deserialization. This lets us read straight from the stream,
                    // minimizing memory use and adding the potential for multithreading
                    // Deserialization will complete in IDeferredDeserializer.FinishDeserialization()
                    deferredFormatter.AddDeferredObject(this, this.length);
                }
                else if (deferred && deferredFormatter == null)
                {
                    throw new InvalidOperationException("stream has deferred serialization streams, but a DeferredFormatter was not provided");
                }
                else
                {
                    this.voidStar = Allocate(this.length).ToPointer();
                    this.valid    = true;

                    // Non-deferred format serializes one big byte[] chunk. This is also
                    // how PDN files were saved with v2.1 Beta 2 and before.
                    byte[] array = (byte[])info.GetValue("pointerData", typeof(byte[]));

                    fixed(byte *pbArray = array)
                    {
                        Memory.Copy(this.VoidStar, (void *)pbArray, (ulong)array.LongLength);
                    }
                }
            }
        }