Ejemplo n.º 1
0
        private unsafe MemoryBlock(SerializationInfo info, StreamingContext context)
        {
            this._length = !info.ContainsEntry("length64") ? (long)info.GetInt32("length") : info.GetInt64("length64");

            if (info.ContainsEntry("bitmapWidth"))
            {
                int width  = info.GetInt32("bitmapWidth");
                int height = info.GetInt32("bitmapHeight");
                if ((width != 0 || height != 0) && (long)width * (long)height * 4L != this._length)
                {
                    throw new ApplicationException("Invalid file format: width * height * 4 != length");
                }
            }

            if (info.GetBoolean("hasParent"))
            {
                this._parentBlock = (MemoryBlock)info.GetValue("parentBlock", typeof(MemoryBlock));
                long parentOffset;
                try
                {
                    parentOffset = info.GetInt64("parentOffset64");
                }
                catch (SerializationException ex)
                {
                    parentOffset = (long)info.GetInt32("parentOffset");
                }
                this._valid = true;
            }
            else
            {
                DeferredDeserializer deferredFormatter = context.Context as DeferredDeserializer;
                bool deferred = false;

                info.TryGetValue("deferred", out deferred);

                if (deferred && deferredFormatter != null)
                {
                    // set this object up for deferred deserialization
                    this._buffer = new byte[this._length];
                    deferredFormatter.AddDeferredObject(this);
                }
                else if (deferred && deferredFormatter == null)
                {
                    throw new InvalidOperationException("stream has deferred serialization streams, but a DeferredFormatter was not provided");
                }
                else
                {
                    // not deferred, so load
                    this._buffer = new byte[this._length];
                    this._valid  = true;
                    bool processed = false;
                    if (info.ContainsEntry("pointerData"))
                    {
                        try
                        {
                            byte[] numArray = (byte[])info.GetValue("pointerData", typeof(byte[]));
                            Array.Copy(numArray, 0, _buffer, 0, numArray.LongLength);
                            processed = true;
                        }
                        catch (SerializationException ex)
                        {
                            processed = false;
                        }
                    }
                    if (processed)
                    {
                        return;
                    }

                    uint chunkCount  = info.GetUInt32("chunkCount");
                    int  chunkFormat = info.GetInt32("chunkFormat");
                    if (chunkFormat != 0)
                    {
                        throw new FormatException("Invalid chunkFormat. Expected 0, but got " + chunkFormat.ToString());
                    }
                    long num = 0;
                    for (uint index = 0; index < chunkCount; ++index)
                    {
                        string name     = "chunk" + index.ToString((IFormatProvider)CultureInfo.InvariantCulture);
                        byte[] numArray = info.GetValue <byte[]>(name);

                        fixed(byte *numPtr = numArray)
                        Array.Copy(numArray, 0, _buffer, num, numArray.LongLength);

                        num += numArray.LongLength;
                    }
                    if (num != this._length)
                    {
                        throw new FormatException(string.Format("length={0}, but all the chunks only account for {1} bytes", (object)this._length.ToString("N0"), (object)num.ToString("N0")));
                    }
                }
            }
        }
Ejemplo n.º 2
0
 private unsafe void DecompressChunk(byte[] compressedBytes, uint chunkSize, long chunkOffset, DeferredDeserializer deferredFormatter)
 {
     using (GZipStream input = new GZipStream((Stream) new MemoryStream(compressedBytes, false), CompressionMode.Decompress, true))
     {
         input.Read(_buffer, (int)chunkOffset, (int)chunkSize);
     }
 }
Ejemplo n.º 3
0
        public unsafe void FinishDeserialization(Stream input, DeferredDeserializer formatter)
        {
            this._valid = true;
            int chunkFormat = input.ReadByte();

            switch (chunkFormat)
            {
            case -1:
                throw new EndOfStreamException();

            case 0:
                goto case 1;

            case 1:
            {
                uint chunkSize = MemoryBlock.ReadUInt(input);

                uint chunkCount = (uint)((ulong)(this._length + (long)chunkSize - 1L) / (ulong)chunkSize);

                bool[] flagArray = new bool[chunkCount];

                for (uint index = 0; index < chunkCount; ++index)
                {
                    uint chunkNumber = MemoryBlock.ReadUInt(input);

                    if (chunkNumber >= chunkCount)
                    {
                        throw new SerializationException(string.Format("chunkNumber ({0}) read from stream is out of bounds (chunkCount = {1})", (object)chunkNumber, (object)chunkCount));
                    }

                    if (flagArray [chunkNumber])
                    {
                        throw new SerializationException("already encountered chunk #" + chunkNumber.ToString());
                    }

                    flagArray [chunkNumber] = true;
                    uint readLen         = MemoryBlock.ReadUInt(input);
                    long chunkOffset     = (long)chunkNumber * (long)chunkSize;
                    uint actualChunkSize = Math.Min(chunkSize, (uint)(this._length - chunkOffset));

                    if (chunkOffset < 0L || chunkOffset >= this._length || chunkOffset + (long)actualChunkSize > this._length)
                    {
                        throw new SerializationException("data was specified to be out of bounds");
                    }

                    byte[] numArray = new byte[readLen];
                    input.ProperRead(numArray, 0, numArray.Length);

                    if (chunkFormat == 0)
                    {
                        try
                        {
                            this.DecompressChunk(numArray, actualChunkSize, chunkOffset, formatter);
                        }
                        catch (Exception ex)
                        {
                            throw new SerializationException("Exception thrown by worker thread", ex);
                        }
                    }
                    else
                    {
                        Array.Copy(numArray, 0, _buffer, chunkOffset, actualChunkSize);
                    }
                }
            }
            break;

            default:
                throw new SerializationException("formatVersion was neither zero nor one");
            }
        }
        public static Document FromStream(Stream stream)
        {
            long streamStartPos = stream.Position;
            bool hasXmlHeader   = true;

            // check the file header
            for (int index = 0; index < Document.MagicBytes.Length; ++index)
            {
                int num = stream.ReadByte();
                if (num == -1)
                {
                    throw new EndOfStreamException();
                }

                if (num != (int)Document.MagicBytes[index])
                {
                    hasXmlHeader = false;
                    break;
                }
            }


            XmlDocument xmlDocument = (XmlDocument)null;

            if (hasXmlHeader)
            {
                int num1 = stream.ReadByte();
                if (num1 == -1)
                {
                    throw new EndOfStreamException();
                }
                int num2 = stream.ReadByte();
                if (num2 == -1)
                {
                    throw new EndOfStreamException();
                }
                int num3 = stream.ReadByte();
                if (num3 == -1)
                {
                    throw new EndOfStreamException();
                }
                int    count    = num1 + (num2 << 8) + (num3 << 16);
                byte[] numArray = new byte[count];
                int    num4     = stream.ProperRead(numArray, 0, count);
                if (num4 != count)
                {
                    throw new EndOfStreamException("expected " + (object)count + " bytes, but only got " + (object)num4);
                }
                string @string = Encoding.UTF8.GetString(numArray);
                xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(@string);
            }
            else
            {
                // no XML header, so go back to the start of the stream
                stream.Position = streamStartPos;
            }

            long dataStartPos = stream.Position;

            int dataByte1 = stream.ReadByte();

            if (dataByte1 == -1)
            {
                throw new EndOfStreamException();
            }

            int dataByte2 = stream.ReadByte();

            if (dataByte2 == -1)
            {
                throw new EndOfStreamException();
            }

            // we're not at the end of the stream, so setup the deserializer
            BinaryFormatter binaryFormatter = new BinaryFormatter();

            // use our custom binder to convert from the Paint.net classes to out internal classes
            var serializationBinder = GetCustomSerializationBinder();

            serializationBinder.SetNextRequiredBaseType(typeof(Document));

            binaryFormatter.Binder = (SerializationBinder)serializationBinder;

            Document document;

            if ((dataByte1 == DEFERRED_HEADER_BYTE1) && (dataByte2 == DEFERRED_HEADER_BYTE2))
            {
                //use deferred serialization - it means the file data is not sequential

                DeferredDeserializer deferredDeserializer = new DeferredDeserializer();
                binaryFormatter.Context = new StreamingContext(binaryFormatter.Context.State, deferredDeserializer);

                // deserialize the document
                document = (Document)binaryFormatter.UnsafeDeserialize(stream, null);

                // then complete the deserialization
                deferredDeserializer.FinishDeserialization(stream);
            }
            else
            {
                // otherwise we can directly deserialise the date from a GZip stream
                // if it matches the correct header bytes
                if (dataByte1 != GZIP_HEADER_BYTE1 || dataByte2 != GZIP_HEADER_BYTE2)
                {
                    throw new FormatException("File is not a valid Paint.net document");
                }

                stream.Position = dataStartPos;
                using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, true))
                {
                    document = (Document)binaryFormatter.UnsafeDeserialize((Stream)gzipStream, (HeaderHandler)null);
                }
            }

            document.HeaderXml = xmlDocument;
            return(document);
        }