private DataElement ContinueReadingSparseArray(
            BinaryReader reader,
            DataElement firstElement,
            int[] dimensions,
            string name)
        {
            var sparseArrayFlags = ReadSparseArrayFlags(firstElement);
            var rowIndex         = Read(reader) as MiNum <int> ??
                                   throw new HandlerException("Unexpected type in row indices of a sparse array.");
            var columnIndex = Read(reader) as MiNum <int> ??
                              throw new HandlerException("Unexpected type in column indices of a sparse array.");
            var data = Read(reader);

            if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsLogical))
            {
                return(DataElementConverter.ConvertToMatSparseArrayOf <bool>(
                           sparseArrayFlags,
                           dimensions,
                           name,
                           rowIndex.Data,
                           columnIndex.Data,
                           data));
            }

            if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsComplex))
            {
                var imaginaryData = Read(reader);
                return(DataElementConverter.ConvertToMatSparseArrayOfComplex(
                           sparseArrayFlags,
                           dimensions,
                           name,
                           rowIndex.Data,
                           columnIndex.Data,
                           data,
                           imaginaryData));
            }

            switch (data)
            {
            case MiNum <double> _:
                return(DataElementConverter.ConvertToMatSparseArrayOf <double>(
                           sparseArrayFlags,
                           dimensions,
                           name,
                           rowIndex.Data,
                           columnIndex.Data,
                           data));

            default:
                throw new NotSupportedException("Only double and logical sparse arrays are supported.");
            }
        }
        private DataElement ReadMatrix(Tag tag, BinaryReader reader)
        {
            if (tag.Length == 0)
            {
                return(MatArray.Empty());
            }

            var element1 = Read(reader);
            var flags    = ReadArrayFlags(element1);

            if (flags.Class == ArrayType.MxOpaque)
            {
                return(ContinueReadingOpaque(reader));
            }

            var element2 = Read(reader) as MiNum <int> ??
                           throw new HandlerException("Unexpected type in array dimensions data.");
            var dimensions = ReadDimensionsArray(element2);
            var element3   = Read(reader) as MiNum <sbyte> ?? throw new HandlerException("Unexpected type in array name.");
            var name       = ReadName(element3);

            if (flags.Class == ArrayType.MxCell)
            {
                return(ContinueReadingCellArray(reader, flags, dimensions, name));
            }

            if (flags.Class == ArrayType.MxSparse)
            {
                return(ContinueReadingSparseArray(reader, element1, dimensions, name));
            }

            var         element4      = Read(reader);
            var         data          = ReadData(element4);
            DataElement imaginaryData = null;

            if (flags.Variable.HasFlag(Variable.IsComplex))
            {
                var element5 = Read(reader);
                imaginaryData = ReadData(element5);
            }

            if (flags.Class == ArrayType.MxStruct)
            {
                var fieldNameLengthElement = data as MiNum <int> ??
                                             throw new HandlerException(
                                                       "Unexpected type in structure field name length.");
                return(ContinueReadingStructure(reader, flags, dimensions, name, fieldNameLengthElement.Data[0]));
            }

            switch (flags.Class)
            {
            case ArrayType.MxChar:
                switch (data)
                {
                case MiNum <byte> _:
                    return(DataElementConverter.ConvertToMatNumericalArrayOf <byte>(
                               flags,
                               dimensions,
                               name,
                               data,
                               imaginaryData));

                case MiNum <ushort> _:
                    return(DataElementConverter.ConvertToMatNumericalArrayOf <ushort>(
                               flags,
                               dimensions,
                               name,
                               data,
                               imaginaryData));

                default:
                    throw new NotSupportedException(
                              $"This type of char array ({data.GetType()}) is not supported.");
                }

            case ArrayType.MxInt8:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <sbyte>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxUInt8:
                if (flags.Variable.HasFlag(Variable.IsLogical))
                {
                    return(DataElementConverter.ConvertToMatNumericalArrayOf <bool>(
                               flags,
                               dimensions,
                               name,
                               data,
                               imaginaryData));
                }

                return(DataElementConverter.ConvertToMatNumericalArrayOf <byte>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxInt16:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <short>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxUInt16:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <ushort>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxInt32:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <int>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxUInt32:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <uint>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxInt64:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <long>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxUInt64:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <ulong>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxSingle:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <float>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            case ArrayType.MxDouble:
                return(DataElementConverter.ConvertToMatNumericalArrayOf <double>(
                           flags,
                           dimensions,
                           name,
                           data,
                           imaginaryData));

            default:
                throw new HandlerException("Unknown data type.");
            }
        }