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"))); } } } }
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); } }
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); }