Example #1
0
        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(0);             // 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;
            }
        }
Example #2
0
        // Reads an array, decompressing it if required
        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);
        }