void WriteArray(Array array, Type elementType, PropertyWriter writer) { stream.Write(array.Length); var size = array.Length * Marshal.SizeOf(elementType); bool compress = size >= CompressionThreshold; stream.Write(compress ? 1 : 0); var sw = stream; DeflateWithChecksum codec = null; var compressLengthPos = stream.BaseStream.Position; stream.Write(size); // Placeholder compressed length var dataStart = stream.BaseStream.Position; if (compress) { stream.Write(new byte[] { 0x58, 0x85 }, 0, 2); // Header bytes for DeflateStream settings codec = new DeflateWithChecksum(stream.BaseStream, CompressionMode.Compress, true); sw = new BinaryWriter(codec); } foreach (var obj in array) { writer(sw, obj); } if (compress) { codec.Close(); // This is important - otherwise bytes can be incorrect var checksum = codec.Checksum; byte[] bytes = { (byte)((checksum >> 24) & 0xFF), (byte)((checksum >> 16) & 0xFF), (byte)((checksum >> 8) & 0xFF), (byte)(checksum & 0xFF), }; stream.Write(bytes); } // Now we can write the compressed data length, since we know the size if (compress) { var dataEnd = stream.BaseStream.Position; stream.BaseStream.Position = compressLengthPos; stream.Write((int)(dataEnd - dataStart)); stream.BaseStream.Position = dataEnd; } }
// Reads an array, decompressing it if required private Array readArray(ReadPrimitive readPrimitive, Type arrayType) { var len = _stream.ReadInt32(); var encoding = _stream.ReadInt32(); var compressedLen = _stream.ReadInt32(); var ret = Array.CreateInstance(arrayType, len); var s = _stream; var endPos = _stream.BaseStream.Position + compressedLen; if (encoding != 0) { if (_errorLevel >= ErrorLevel.Checked) { if (encoding != 1) { throw new FbxException(_stream.BaseStream.Position - 1, "Invalid compression encoding (must be 0 or 1)"); } var cmf = _stream.ReadByte(); if ((cmf & 0xF) != 8 || (cmf >> 4) > 7) { throw new FbxException(_stream.BaseStream.Position - 1, "Invalid compression format " + cmf); } var flg = _stream.ReadByte(); if (_errorLevel >= ErrorLevel.Strict && ((cmf << 8) + flg) % 31 != 0) { throw new FbxException(_stream.BaseStream.Position - 1, "Invalid compression FCHECK"); } if ((flg & (1 << 5)) != 0) { throw new FbxException(_stream.BaseStream.Position - 1, "Invalid compression flags; dictionary not supported"); } } else { _stream.BaseStream.Position += 2; } var codec = new DeflateWithChecksum(_stream.BaseStream, CompressionMode.Decompress); s = new BinaryReader(codec); } try { for (int i = 0; i < len; i++) { ret.SetValue(readPrimitive(s), i); } } catch (InvalidDataException) { throw new FbxException(_stream.BaseStream.Position - 1, "Compressed data was malformed"); } if (encoding != 0) { if (_errorLevel >= ErrorLevel.Checked) { _stream.BaseStream.Position = endPos - sizeof(int); var checksumBytes = new byte[sizeof(int)]; _stream.BaseStream.Read(checksumBytes, 0, checksumBytes.Length); int checksum = 0; for (int i = 0; i < checksumBytes.Length; i++) { checksum = (checksum << 8) + checksumBytes[i]; } if (checksum != ((DeflateWithChecksum)s.BaseStream).Checksum) { throw new FbxException(_stream.BaseStream.Position, "Compressed data has invalid checksum"); } } else { _stream.BaseStream.Position = endPos; } } return(ret); }