Exemplo n.º 1
0
        /// <summary>
        /// <seealso cref="Marshal.ProcessPackedRow"/>
        ///
        /// Opcodes supported:
        /// <seealso cref="Opcode.PackedRow"/>
        /// </summary>
        /// <param name="opcode">Type of object to parse</param>
        /// <returns>The decoded python type</returns>
        /// <exception cref="InvalidDataException">If any error was found in the data</exception>
        protected virtual PyDataType ProcessPackedRow(Opcode opcode)
        {
            if (opcode != Opcode.PackedRow)
            {
                throw new InvalidDataException($"Trying to parse a {opcode} as PackedRow");
            }

            DBRowDescriptor descriptor           = this.Process(false);
            Dictionary <string, PyDataType> data = new Dictionary <string, PyDataType> ();
            int wholeBytes = 0;
            int nullBits   = 0;
            int boolBits   = 0;

            List <DBRowDescriptor.Column> booleanColumns = new List <DBRowDescriptor.Column>();

            foreach (DBRowDescriptor.Column column in descriptor.Columns)
            {
                int bitLength = Utils.GetTypeBits(column.Type);

                if (column.Type == FieldType.Bool)
                {
                    booleanColumns.Add(column);
                    boolBits++;
                }

                nullBits++;

                if (bitLength >= 8)
                {
                    wholeBytes += bitLength >> 3;
                }
            }

            // sort columns by the bit size and calculate other statistics for the PackedRow
            IOrderedEnumerable <DBRowDescriptor.Column> enumerator = descriptor.Columns.OrderByDescending(c => Utils.GetTypeBits(c.Type));

            MemoryStream decompressedStream = ZeroCompressionUtils.LoadZeroCompressed(this.mReader, wholeBytes + ((nullBits + boolBits) >> 3) + 1);
            BinaryReader decompressedReader = new BinaryReader(decompressedStream);

            byte[] fullBuffer = decompressedStream.GetBuffer();

            foreach (DBRowDescriptor.Column column in enumerator)
            {
                int  bit    = (wholeBytes << 3) + descriptor.Columns.IndexOf(column) + boolBits;
                bool isNull = (fullBuffer[bit >> 3] & (1 << (bit & 0x7))) == (1 << (bit & 0x7));

                switch (column.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    data[column.Name] = new PyInteger(decompressedReader.ReadInt64());
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    data[column.Name] = new PyInteger(decompressedReader.ReadInt32());
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    data[column.Name] = new PyInteger(decompressedReader.ReadInt16());
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    data[column.Name] = new PyInteger(decompressedReader.ReadByte());
                    break;

                case FieldType.R8:
                    data[column.Name] = new PyDecimal(decompressedReader.ReadDouble());
                    break;

                case FieldType.R4:
                    data[column.Name] = new PyDecimal(decompressedReader.ReadSingle());
                    break;

                case FieldType.Bool:
                {
                    int  boolBit = (wholeBytes << 3) + booleanColumns.IndexOf(column);
                    bool isTrue  = (fullBuffer[boolBit >> 3] & (1 << (boolBit & 0x7))) == (1 << (boolBit & 0x7));

                    data[column.Name] = new PyBool(isTrue);
                }
                break;

                case FieldType.Bytes:
                case FieldType.WStr:
                case FieldType.Str:
                    data[column.Name] = this.Process(false);
                    break;

                default:
                    throw new InvalidDataException($"Unknown column type {column.Type}");
                }

                if (isNull == true)
                {
                    data[column.Name] = null;
                }
            }

            return(new PyPackedRow(descriptor, data));
        }
Exemplo n.º 2
0
        /// <summary>
        /// <seealso cref="Marshal.ProcessPackedRow"/>
        ///
        /// Opcodes supported:
        /// <seealso cref="Opcode.PackedRow"/>
        /// </summary>
        /// <param name="opcode">Type of object to parse</param>
        /// <returns>The decoded python type</returns>
        /// <exception cref="InvalidDataException">If any error was found in the data</exception>
        protected virtual PyDataType ProcessPackedRow(Opcode opcode)
        {
            if (opcode != Opcode.PackedRow)
            {
                throw new InvalidDataException($"Trying to parse a {opcode} as PackedRow");
            }

            DBRowDescriptor descriptor           = this.Process(false);
            Dictionary <string, PyDataType> data = new Dictionary <string, PyDataType> ();

            MemoryStream decompressedStream = ZeroCompressionUtils.LoadZeroCompressed(this.mReader);
            BinaryReader decompressedReader = new BinaryReader(decompressedStream);

            // sort columns by the bit size
            IEnumerable <DBRowDescriptor.Column> enumerator =
                descriptor.Columns.OrderByDescending(c => Utils.GetTypeBits(c.Type));

            int  bitOffset = 8;
            byte buffer    = 0;

            foreach (DBRowDescriptor.Column column in enumerator)
            {
                switch (column.Type)
                {
                case FieldType.I8:
                case FieldType.UI8:
                case FieldType.CY:
                case FieldType.FileTime:
                    data[column.Name] = new PyInteger(decompressedReader.ReadInt64());
                    break;

                case FieldType.I4:
                case FieldType.UI4:
                    data[column.Name] = new PyInteger(decompressedReader.ReadInt32());
                    break;

                case FieldType.I2:
                case FieldType.UI2:
                    data[column.Name] = new PyInteger(decompressedReader.ReadInt16());
                    break;

                case FieldType.I1:
                case FieldType.UI1:
                    data[column.Name] = new PyInteger(decompressedReader.ReadByte());
                    break;

                case FieldType.R8:
                    data[column.Name] = new PyDecimal(decompressedReader.ReadDouble());
                    break;

                case FieldType.R4:
                    data[column.Name] = new PyDecimal(decompressedReader.ReadSingle());
                    break;

                case FieldType.Bool:
                    // read a byte from the buffer if needed
                    if (bitOffset == 8)
                    {
                        buffer    = decompressedReader.ReadByte();
                        bitOffset = 0;
                    }

                    data[column.Name] = new PyBool(((buffer >> bitOffset++) & 0x01) == 0x01);
                    break;

                case FieldType.Bytes:
                case FieldType.WStr:
                case FieldType.Str:
                    data[column.Name] = this.Process(false);
                    break;

                default:
                    throw new InvalidDataException($"Unknown column type {column.Type}");
                }
            }

            return(new PyPackedRow(descriptor, data));
        }