Warning, file /education/labplot/src/backend/datasources/filters/MatioFilter.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     File                 : MatioFilter.cpp
0003     Project              : LabPlot
0004     Description          : Matio I/O-filter
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2021-2022 Stefan Gerlach <stefan.gerlach@uni.kn>
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "MatioFilter.h"
0010 #include "MatioFilterPrivate.h"
0011 #include "backend/core/column/Column.h"
0012 #include "backend/lib/XmlStreamReader.h"
0013 #include "backend/lib/macros.h"
0014 #include "backend/lib/trace.h"
0015 #include "backend/matrix/Matrix.h"
0016 
0017 #include <KLocalizedString>
0018 
0019 #include <cmath>
0020 
0021 ///////////// macros ///////////////////////////////////////////////
0022 
0023 // see NetCDFFilter.cpp
0024 // type - var data type, dtype - container data type
0025 #define MAT_READ_VAR(type, dtype)                                                                                                                              \
0026     {                                                                                                                                                          \
0027         if (var->isComplex) {                                                                                                                                  \
0028             auto* complex_data = (mat_complex_split_t*)var->data;                                                                                              \
0029             auto* re = (type*)complex_data->Re;                                                                                                                \
0030             auto* im = (type*)complex_data->Im;                                                                                                                \
0031             if (dataSource) {                                                                                                                                  \
0032                 for (size_t i = 0; i < actualRows; i++)                                                                                                        \
0033                     for (size_t j = 0; j < actualCols / 2; j++) {                                                                                              \
0034                         const size_t index = i + startRow - 1 + (j + startColumn - 1) * rows;                                                                  \
0035                         static_cast<QVector<dtype>*>(dataContainer[(int)(2 * j)])->operator[](i) = re[index];                                                  \
0036                         static_cast<QVector<dtype>*>(dataContainer[(int)(2 * j + 1)])->operator[](i) = im[index];                                              \
0037                     }                                                                                                                                          \
0038             } else { /* preview */                                                                                                                             \
0039                 QStringList header;                                                                                                                            \
0040                 for (size_t j = 0; j < actualCols / 2; j++) {                                                                                                  \
0041                     header << QLatin1String("Re ") + QString::number(j + 1) << QLatin1String("Im ") + QString::number(j + 1);                                  \
0042                 }                                                                                                                                              \
0043                 dataStrings << header;                                                                                                                         \
0044                 for (size_t i = 0; i < std::min(actualRows, lines); i++) {                                                                                     \
0045                     QStringList row;                                                                                                                           \
0046                     for (size_t j = 0; j < actualCols / 2; j++) {                                                                                              \
0047                         const size_t index = i + startRow - 1 + (j + startColumn - 1) * rows;                                                                  \
0048                         row << QString::number(re[index]) << QString::number(im[index]);                                                                       \
0049                     }                                                                                                                                          \
0050                     dataStrings << row;                                                                                                                        \
0051                 }                                                                                                                                              \
0052             }                                                                                                                                                  \
0053         } else {                                                                                                                                               \
0054             const auto* data = static_cast<const type*>(var->data);                                                                                            \
0055             if (dataSource) {                                                                                                                                  \
0056                 for (size_t i = 0; i < actualRows; i++)                                                                                                        \
0057                     for (size_t j = 0; j < actualCols; j++) {                                                                                                  \
0058                         const size_t index = i + startRow - 1 + (j + startColumn - 1) * rows;                                                                  \
0059                         static_cast<QVector<dtype>*>(dataContainer[(int)j + (dynamic_cast<Matrix*>(dataSource) ? columnOffset : 0)])->operator[](i) =          \
0060                             data[index];                                                                                                                       \
0061                     }                                                                                                                                          \
0062             } else { /* preview */                                                                                                                             \
0063                 for (size_t i = 0; i < std::min(actualRows, lines); i++) {                                                                                     \
0064                     QStringList row;                                                                                                                           \
0065                     for (size_t j = 0; j < actualCols; j++)                                                                                                    \
0066                         row << QString::number(data[i + startRow - 1 + (j + startColumn - 1) * rows]);                                                         \
0067                     dataStrings << row;                                                                                                                        \
0068                 }                                                                                                                                              \
0069             }                                                                                                                                                  \
0070         }                                                                                                                                                      \
0071     }
0072 
0073 // type - cell data type, dtype - container data type
0074 // TODO: complex
0075 #define MAT_READ_CELL(type, dtype)                                                                                                                             \
0076     {                                                                                                                                                          \
0077         const auto* data = (const type*)cell->data;                                                                                                            \
0078         if (dataSource) {                                                                                                                                      \
0079             if (i + startRow - 1 < cellsize)                                                                                                                   \
0080                 static_cast<QVector<dtype>*>(dataContainer[j])->operator[](i) = data[i + startRow - 1];                                                        \
0081             else                                                                                                                                               \
0082                 static_cast<QVector<dtype>*>(dataContainer[j])->operator[](i) = qQNaN();                                                                       \
0083         } else { /* preview */                                                                                                                                 \
0084             if (i + startRow - 1 < cellsize)                                                                                                                   \
0085                 row << QString::number(data[i + startRow - 1]);                                                                                                \
0086             else                                                                                                                                               \
0087                 row << QString();                                                                                                                              \
0088         }                                                                                                                                                      \
0089     }
0090 
0091 // type - sparse data type, dtype - container data type
0092 #define MAT_READ_SPARSE(type, dtype)                                                                                                                           \
0093     {                                                                                                                                                          \
0094         /* set default values */                                                                                                                               \
0095         QVector<QVector<type>> matrix; /* for preview */                                                                                                       \
0096         if (dataSource) {                                                                                                                                      \
0097             for (size_t i = 0; i < actualRows; i++)                                                                                                            \
0098                 for (size_t j = 0; j < actualCols; j++)                                                                                                        \
0099                     static_cast<QVector<dtype>*>(dataContainer[j])->operator[](i) = 0;                                                                         \
0100         } else { /* preview (full matrix need to store values) */                                                                                              \
0101             for (size_t i = 0; i < actualEndRow; i++) {                                                                                                        \
0102                 QVector<type> tmp;                                                                                                                             \
0103                 for (size_t j = 0; j < actualEndColumn; j++)                                                                                                   \
0104                     tmp.append(0);                                                                                                                             \
0105                 matrix.append(tmp);                                                                                                                            \
0106             }                                                                                                                                                  \
0107         }                                                                                                                                                      \
0108         if (var->isComplex) {                                                                                                                                  \
0109             auto* complex_data = (mat_complex_split_t*)sparse->data;                                                                                           \
0110             auto* re = (type*)complex_data->Re;                                                                                                                \
0111             auto* im = (type*)complex_data->Im;                                                                                                                \
0112             if (dataSource) {                                                                                                                                  \
0113                 for (size_t i = 0; i < std::min((size_t)sparse->njc - 1, actualCols / 2); i++)                                                                 \
0114                     for (size_t j = sparse->jc[i]; j < (size_t)sparse->jc[i + 1] && j < (size_t)sparse->ndata; j++) {                                          \
0115                         if (sparse->ir[j] >= (size_t)startRow - 1 && sparse->ir[j] < actualEndRow) { /* only read requested rows */                            \
0116                             static_cast<QVector<dtype>*>(dataContainer[(int)2 * i])->operator[](sparse->ir[j] - startRow + 1) =                                \
0117                                 *(re + j * stride / sizeof(type));                                                                                             \
0118                             static_cast<QVector<dtype>*>(dataContainer[(int)2 * i + 1])->operator[](sparse->ir[j] - startRow + 1) =                            \
0119                                 *(im + j * stride / sizeof(type));                                                                                             \
0120                         }                                                                                                                                      \
0121                     }                                                                                                                                          \
0122             } else { /* preview */                                                                                                                             \
0123                 for (size_t i = 0; i < std::min((size_t)sparse->njc - 1, actualEndColumn / 2 + 1); i++)                                                        \
0124                     for (size_t j = sparse->jc[i]; j < (size_t)sparse->jc[i + 1] && j < (size_t)sparse->ndata; j++) {                                          \
0125                         if (sparse->ir[j] >= (size_t)startRow - 1 && sparse->ir[j] < actualEndRow) { /* only read requested rows */                            \
0126                             if (2 * i < actualEndColumn) /* Im may be last col */                                                                              \
0127                                 matrix[sparse->ir[j]][2 * i] = *(re + j * stride / sizeof(type));                                                              \
0128                             if (2 * i + 1 < actualEndColumn) /* Re may be last col */                                                                          \
0129                                 matrix[sparse->ir[j]][2 * i + 1] = *(im + j * stride / sizeof(type));                                                          \
0130                         }                                                                                                                                      \
0131                     }                                                                                                                                          \
0132             }                                                                                                                                                  \
0133         } else { /* real */                                                                                                                                    \
0134             auto* data = (type*)sparse->data;                                                                                                                  \
0135             if (dataSource) {                                                                                                                                  \
0136                 for (size_t i = startColumn - 1; i < std::min((size_t)sparse->njc - 1, actualEndColumn); i++)                                                  \
0137                     for (size_t j = sparse->jc[i]; j < (size_t)sparse->jc[i + 1] && j < (size_t)sparse->ndata; j++) {                                          \
0138                         if (sparse->ir[j] >= (size_t)startRow - 1 && sparse->ir[j] < actualEndRow) /* only read requested rows */                              \
0139                             static_cast<QVector<dtype>*>(dataContainer[(int)i - startColumn + 1])->operator[](sparse->ir[j] - startRow + 1) =                  \
0140                                 *(data + j * stride / sizeof(type));                                                                                           \
0141                     }                                                                                                                                          \
0142             } else { /* preview */                                                                                                                             \
0143                 for (size_t i = 0; i < std::min((size_t)sparse->njc - 1, actualEndColumn); i++)                                                                \
0144                     for (size_t j = sparse->jc[i]; j < (size_t)sparse->jc[i + 1] && j < (size_t)sparse->ndata; j++)                                            \
0145                         if (sparse->ir[j] < actualEndRow) /* don't read beyond last row */                                                                     \
0146                             matrix[sparse->ir[j]][i] = *(data + j * stride / sizeof(type));                                                                    \
0147             }                                                                                                                                                  \
0148         }                                                                                                                                                      \
0149         if (!dataSource) { /* preview */                                                                                                                       \
0150             for (size_t i = startRow - 1; i < std::min(actualEndRow, lines); i++) {                                                                            \
0151                 QStringList row;                                                                                                                               \
0152                 for (size_t j = startColumn - 1; j < actualEndColumn; j++)                                                                                     \
0153                     row << QString::number(matrix[i][j]);                                                                                                      \
0154                 dataStrings << row;                                                                                                                            \
0155             }                                                                                                                                                  \
0156         }                                                                                                                                                      \
0157     }
0158 
0159 // type - struct data type
0160 #define MAT_READ_STRUCT(type)                                                                                                                                  \
0161     {                                                                                                                                                          \
0162         if (fields[i]->isComplex) {                                                                                                                            \
0163             auto* complex_data = (mat_complex_split_t*)fields[i]->data;                                                                                        \
0164             auto* re = (type*)complex_data->Re;                                                                                                                \
0165             auto* im = (type*)complex_data->Im;                                                                                                                \
0166                                                                                                                                                                \
0167             DEBUG(Q_FUNC_INFO << "  rank = 2 (" << fields[i]->dims[0] << " x " << fields[i]->dims[1] << ")")                                                   \
0168             if (dataSource) {                                                                                                                                  \
0169                 for (size_t j = 0; j < actualRows; j++) {                                                                                                      \
0170                     static_cast<QVector<type>*>(dataContainer[colIndex])->operator[](j) = re[j + startRow - 1];                                                \
0171                     static_cast<QVector<type>*>(dataContainer[colIndex + 1])->operator[](j) = im[j + startRow - 1];                                            \
0172                 }                                                                                                                                              \
0173             } else { /* preview */                                                                                                                             \
0174                 for (size_t j = 0; j < std::min(actualRows, lines); j++) {                                                                                     \
0175                     /* TODO: use when complex column mode is supported */                                                                                      \
0176                     /* if (im[j] < 0)                                                                                                                          \
0177                         dataStrings[j+1][field] = QString::number(re[j]) + QLatin1String(" - ")                                                                \
0178                                     + QString::number(fabs(im[j])) + QLatin1String("i");                                                                       \
0179                     else if (im[j] == 0)                                                                                                                       \
0180                         dataStrings[j+1][field] = QString::number(re[j]);                                                                                      \
0181                     else if (re[j] == 0)                                                                                                                       \
0182                         dataStrings[j+1][field] = QString::number(im[j]) + QLatin1String("i");                                                                 \
0183                     else                                                                                                                                       \
0184                         dataStrings[j+1][field] = QString::number(re[j]) + QLatin1String(" + ")                                                                \
0185                                     + QString::number(im[j]) + QLatin1String("i");                                                                             \
0186                     */                                                                                                                                         \
0187                     dataStrings[j + 1][colIndex] = QString::number(re[j + startRow - 1]);                                                                      \
0188                     dataStrings[j + 1][colIndex + 1] = QString::number(im[j + startRow - 1]);                                                                  \
0189                 }                                                                                                                                              \
0190             }                                                                                                                                                  \
0191             colIndex++; /* complex uses two columns atm */                                                                                                     \
0192         } else { /* real */                                                                                                                                    \
0193             auto* data = (type*)fields[i]->data;                                                                                                               \
0194             DEBUG(Q_FUNC_INFO << "  rank = 2 (" << fields[i]->dims[0] << " x " << fields[i]->dims[1] << ")")                                                   \
0195             if (dataSource) {                                                                                                                                  \
0196                 for (size_t j = 0; j < actualRows; j++)                                                                                                        \
0197                     static_cast<QVector<type>*>(dataContainer[colIndex])->operator[](j) = data[j + startRow - 1];                                              \
0198             } else { /* preview */                                                                                                                             \
0199                 for (size_t j = 0; j < std::min(actualRows, lines); j++)                                                                                       \
0200                     dataStrings[j + 1][colIndex] = QString::number(data[j + startRow - 1]);                                                                    \
0201             }                                                                                                                                                  \
0202         }                                                                                                                                                      \
0203     }
0204 //////////////////////////////////////////////////////////////////////
0205 
0206 /*!
0207     \class MatioFilter
0208     \brief Manages the import/export of data from/to a Matio file.
0209 
0210     \ingroup datasources
0211 */
0212 MatioFilter::MatioFilter()
0213     : AbstractFileFilter(FileType::MATIO)
0214     , d(new MatioFilterPrivate(this)) {
0215 }
0216 
0217 MatioFilter::~MatioFilter() = default;
0218 
0219 /*!
0220   parses the content of the file \c ileName.
0221 */
0222 void MatioFilter::parse(const QString& fileName) {
0223     d->parse(fileName);
0224 }
0225 
0226 /*!
0227   reads the content of the current variable from file \c fileName.
0228 */
0229 QVector<QStringList>
0230 MatioFilter::readCurrentVar(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode, int lines) {
0231     return d->readCurrentVar(fileName, dataSource, importMode, (size_t)lines);
0232 }
0233 
0234 /*!
0235   reads the content of the file \c fileName to the data source \c dataSource.
0236 */
0237 void MatioFilter::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode) {
0238     d->readDataFromFile(fileName, dataSource, mode);
0239 }
0240 
0241 /*!
0242 writes the content of the data source \c dataSource to the file \c fileName.
0243 */
0244 void MatioFilter::write(const QString& fileName, AbstractDataSource* dataSource) {
0245     d->write(fileName, dataSource);
0246     //  emit()
0247 }
0248 
0249 ///////////////////////////////////////////////////////////////////////
0250 
0251 void MatioFilter::setCurrentVarName(const QString& name) {
0252     d->currentVarName = name;
0253     d->selectedVarNames = QStringList() << name;
0254 }
0255 void MatioFilter::setSelectedVarNames(const QStringList& names) {
0256     d->currentVarName = names.first();
0257     d->selectedVarNames = names;
0258 }
0259 const QStringList MatioFilter::selectedVarNames() const {
0260     return d->selectedVarNames;
0261 }
0262 size_t MatioFilter::varCount() const {
0263     return d->varCount;
0264 }
0265 QVector<QStringList> MatioFilter::varsInfo() const {
0266     return d->varsInfo;
0267 }
0268 
0269 void MatioFilter::setStartRow(const int s) {
0270     d->startRow = s;
0271 }
0272 
0273 int MatioFilter::startRow() const {
0274     return d->startRow;
0275 }
0276 
0277 void MatioFilter::setEndRow(const int e) {
0278     d->endRow = e;
0279 }
0280 
0281 int MatioFilter::endRow() const {
0282     return d->endRow;
0283 }
0284 
0285 void MatioFilter::setStartColumn(const int c) {
0286     d->startColumn = c;
0287 }
0288 
0289 int MatioFilter::startColumn() const {
0290     return d->startColumn;
0291 }
0292 
0293 void MatioFilter::setEndColumn(const int c) {
0294     d->endColumn = c;
0295 }
0296 
0297 int MatioFilter::endColumn() const {
0298     return d->endColumn;
0299 }
0300 
0301 QString MatioFilter::fileInfoString(const QString& fileName) {
0302     DEBUG(Q_FUNC_INFO << ", fileName = " << qPrintable(fileName))
0303 
0304     QString info;
0305 #ifdef HAVE_MATIO
0306     mat_t* matfp = Mat_Open(qPrintable(fileName), MAT_ACC_RDONLY);
0307 
0308     if (!matfp)
0309         return i18n("Error getting file info");
0310 
0311     int version = Mat_GetVersion(matfp);
0312     const char* header = Mat_GetHeader(matfp);
0313     DEBUG(Q_FUNC_INFO << ", Header: " << header)
0314     info += QLatin1String(header);
0315     info += QStringLiteral("<br>");
0316     switch (version) {
0317     case MAT_FT_MAT73:
0318         info += i18n("Matlab version 7.3");
0319         break;
0320     case MAT_FT_MAT5:
0321         info += i18n("Matlab version 5");
0322         break;
0323     case MAT_FT_MAT4:
0324         info += i18n("Matlab version 4");
0325         break;
0326     case MAT_FT_UNDEFINED:
0327         info += i18n("Matlab version undefined");
0328     }
0329     info += QLatin1String("<br>");
0330 
0331     size_t n;
0332     char** dir = Mat_GetDir(matfp, &n);
0333     info += i18n("Number of variables: ") + QString::number(n);
0334     info += QStringLiteral("<br>");
0335     if (dir && n < 10) { // only show variable info when there are not too many
0336         info += i18n("Variables:");
0337         for (size_t i = 0; i < n; ++i) {
0338             if (dir[i]) {
0339                 info += QStringLiteral(" \"") + QLatin1String(dir[i]) + QStringLiteral("\"");
0340                 matvar_t* var = Mat_VarReadInfo(matfp, dir[i]);
0341                 if (var)
0342                     info += QStringLiteral(" (") + QString::number(Mat_VarGetNumberOfFields(var)) + QStringLiteral(" fields, ")
0343                         + QString::number(Mat_VarGetSize(var)) + QStringLiteral(" byte)");
0344                 Mat_VarFree(var);
0345             }
0346         }
0347     }
0348 
0349     Mat_Close(matfp);
0350 #else
0351     Q_UNUSED(fileName)
0352 #endif
0353 
0354     return info;
0355 }
0356 
0357 // #####################################################################
0358 // ################### Private implementation ##########################
0359 // #####################################################################
0360 
0361 MatioFilterPrivate::MatioFilterPrivate(MatioFilter*) {
0362 }
0363 
0364 // helper functions
0365 #ifdef HAVE_MATIO
0366 // see matio.h
0367 QString MatioFilterPrivate::className(matio_classes classType) {
0368     switch (classType) {
0369     case MAT_C_EMPTY:
0370         return i18n("Empty");
0371     case MAT_C_CELL:
0372         return i18n("Cell");
0373     case MAT_C_STRUCT:
0374         return i18n("Struct");
0375     case MAT_C_OBJECT:
0376         return i18n("Object");
0377     case MAT_C_CHAR:
0378         return i18n("Char");
0379     case MAT_C_SPARSE:
0380         return i18n("Sparse");
0381     case MAT_C_DOUBLE:
0382         return i18n("Double");
0383     case MAT_C_SINGLE:
0384         return i18n("Single");
0385     case MAT_C_INT8:
0386         return i18n("Int8");
0387     case MAT_C_UINT8:
0388         return i18n("UInt8");
0389     case MAT_C_INT16:
0390         return i18n("Int16");
0391     case MAT_C_UINT16:
0392         return i18n("UInt16");
0393     case MAT_C_INT32:
0394         return i18n("Int32");
0395     case MAT_C_UINT32:
0396         return i18n("UInt32");
0397     case MAT_C_INT64:
0398         return i18n("Int64");
0399     case MAT_C_UINT64:
0400         return i18n("UInt64");
0401     case MAT_C_FUNCTION:
0402         return i18n("Function");
0403     case MAT_C_OPAQUE:
0404         return i18n("Opaque");
0405     }
0406 
0407     return i18n("Undefined");
0408 }
0409 QString MatioFilterPrivate::typeName(matio_types dataType) {
0410     switch (dataType) {
0411     case MAT_T_UNKNOWN:
0412         return i18n("Unknown");
0413     case MAT_T_INT8:
0414         return i18n("Int8");
0415     case MAT_T_UINT8:
0416         return i18n("UInt8");
0417     case MAT_T_INT16:
0418         return i18n("Int16");
0419     case MAT_T_UINT16:
0420         return i18n("UInt16");
0421     case MAT_T_INT32:
0422         return i18n("Int32");
0423     case MAT_T_UINT32:
0424         return i18n("UInt32");
0425     case MAT_T_SINGLE:
0426         return i18n("Single");
0427     case MAT_T_DOUBLE:
0428         return i18n("Double");
0429     case MAT_T_INT64:
0430         return i18n("Int64");
0431     case MAT_T_UINT64:
0432         return i18n("UInt64");
0433     case MAT_T_MATRIX:
0434         return i18n("Matrix");
0435     case MAT_T_COMPRESSED:
0436         return i18n("Compressed");
0437     case MAT_T_UTF8:
0438         return i18n("UTF8");
0439     case MAT_T_UTF16:
0440         return i18n("UTF16");
0441     case MAT_T_UTF32:
0442         return i18n("UTF32");
0443     case MAT_T_STRING:
0444         return i18n("String");
0445     case MAT_T_CELL:
0446         return i18n("Cell");
0447     case MAT_T_STRUCT:
0448         return i18n("Struct");
0449     case MAT_T_ARRAY:
0450         return i18n("Array");
0451     case MAT_T_FUNCTION:
0452         return i18n("Function");
0453     }
0454 
0455     return i18n("Undefined");
0456 }
0457 
0458 AbstractColumn::ColumnMode MatioFilterPrivate::classMode(matio_classes classType) {
0459     switch (classType) {
0460     case MAT_C_INT8:
0461     case MAT_C_UINT8:
0462     case MAT_C_INT16:
0463     case MAT_C_UINT16:
0464     case MAT_C_INT32:
0465     case MAT_C_UINT32:
0466         return AbstractColumn::ColumnMode::Integer;
0467         break;
0468     case MAT_C_INT64:
0469     case MAT_C_UINT64:
0470         return AbstractColumn::ColumnMode::BigInt;
0471         break;
0472     case MAT_C_CHAR:
0473         return AbstractColumn::ColumnMode::Text;
0474         break;
0475     case MAT_C_EMPTY:
0476     case MAT_C_CELL:
0477     case MAT_C_STRUCT:
0478     case MAT_C_OBJECT:
0479     case MAT_C_SPARSE:
0480     case MAT_C_DOUBLE:
0481     case MAT_C_SINGLE:
0482     case MAT_C_FUNCTION:
0483     case MAT_C_OPAQUE:
0484         break;
0485     }
0486 
0487     return AbstractColumn::ColumnMode::Double;
0488 }
0489 
0490 AbstractColumn::ColumnMode MatioFilterPrivate::typeMode(matio_types dataType) {
0491     switch (dataType) {
0492     case MAT_T_INT8:
0493     case MAT_T_UINT8:
0494     case MAT_T_INT16:
0495     case MAT_T_UINT16:
0496     case MAT_T_INT32:
0497     case MAT_T_UINT32:
0498         return AbstractColumn::ColumnMode::Integer;
0499         break;
0500     case MAT_T_INT64:
0501     case MAT_T_UINT64:
0502         return AbstractColumn::ColumnMode::BigInt;
0503         break;
0504     case MAT_T_SINGLE:
0505     case MAT_T_DOUBLE:
0506     case MAT_T_UNKNOWN:
0507     case MAT_T_MATRIX:
0508     case MAT_T_COMPRESSED:
0509     case MAT_T_UTF8:
0510     case MAT_T_UTF16:
0511     case MAT_T_UTF32:
0512     case MAT_T_STRING:
0513     case MAT_T_CELL:
0514     case MAT_T_STRUCT:
0515     case MAT_T_ARRAY:
0516     case MAT_T_FUNCTION:
0517         break;
0518     }
0519 
0520     return AbstractColumn::ColumnMode::Double;
0521 }
0522 
0523 #endif
0524 
0525 /*!
0526     parses the content of the file \c fileName
0527 */
0528 void MatioFilterPrivate::parse(const QString& fileName) {
0529 #ifdef HAVE_MATIO
0530     DEBUG(Q_FUNC_INFO << ", fileName = " << qPrintable(fileName));
0531 
0532     mat_t* matfp = Mat_Open(qPrintable(fileName), MAT_ACC_RDONLY);
0533     if (!matfp) {
0534         DEBUG(Q_FUNC_INFO << ", ERROR getting file info")
0535         return;
0536     }
0537 
0538     // get names of all vars
0539     char** dir = Mat_GetDir(matfp, &varCount);
0540     DEBUG(Q_FUNC_INFO << ", found " << varCount << " vars")
0541 
0542     varsInfo.clear();
0543     for (size_t i = 0; i < varCount; ++i) {
0544         if (dir[i]) {
0545             QStringList info;
0546 
0547             // name
0548             info << QLatin1String(dir[i]);
0549             // Mat_VarReadInfo() does not determine the data type of sparse
0550             // Don't use Mat_VarRead(matfp, dir[i]). It searches the whole file for every var
0551             matvar_t* var = Mat_VarReadNext(matfp);
0552 
0553             // rank
0554             const int rank = var->rank;
0555             info << QString::number(rank);
0556 
0557             // dims
0558             QString dims;
0559             for (int j = 0; j < rank; j++) {
0560                 if (j > 0)
0561                     dims += QStringLiteral(", ");
0562                 dims += QString::number(var->dims[j]);
0563             }
0564             info << dims;
0565 
0566             // class_type
0567             info << className(var->class_type);
0568 
0569             // data_type
0570             info << typeName(var->data_type);
0571 
0572             // complex/logical
0573             if (var->isComplex)
0574                 info << i18n("Yes");
0575             else
0576                 info << i18n("No");
0577             if (var->isLogical)
0578                 info << i18n("Yes");
0579             else
0580                 info << i18n("No");
0581 
0582             Mat_VarFree(var);
0583             varsInfo.append(info);
0584         }
0585     }
0586     Mat_Close(matfp);
0587 #else
0588     Q_UNUSED(fileName)
0589 #endif
0590 }
0591 
0592 /*!
0593     reads the content of the current selected variable from file \c fileName to the data source \c dataSource.
0594     (Not used for preview)
0595     Uses the settings defined in the data source.
0596 */
0597 void MatioFilterPrivate::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode) {
0598     PERFTRACE(QLatin1String(Q_FUNC_INFO));
0599 
0600     if (currentVarName.isEmpty()) {
0601         DEBUG(Q_FUNC_INFO << ", no variable selected");
0602         return;
0603     }
0604 
0605     QDEBUG(Q_FUNC_INFO << ", selected var names:" << selectedVarNames)
0606 #ifdef HAVE_MATIO
0607     // open file only once
0608     if (!selectedVarNames.isEmpty())
0609         matfp = Mat_Open(qPrintable(fileName), MAT_ACC_RDONLY);
0610 #endif
0611     for (const auto& var : selectedVarNames) {
0612         currentVarName = var;
0613         readCurrentVar(fileName, dataSource, importMode);
0614         importMode = AbstractFileFilter::ImportMode::Append; // append other vars
0615     }
0616 #ifdef HAVE_MATIO
0617     if (matfp) { // only if opened
0618         Mat_Close(matfp);
0619         matfp = nullptr;
0620     }
0621 #endif
0622 }
0623 
0624 /*!
0625     reads the content of the current variable in the file \c fileName to a string (for preview) or to the data source.
0626 */
0627 QVector<QStringList>
0628 MatioFilterPrivate::readCurrentVar(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode, size_t lines) {
0629     PERFTRACE(QLatin1String(Q_FUNC_INFO));
0630     QVector<QStringList> dataStrings;
0631 
0632     if (currentVarName.isEmpty()) {
0633         DEBUG(Q_FUNC_INFO << ", WARNING: current var name is empty!")
0634         return dataStrings << (QStringList() << i18n("No variable selected"));
0635     }
0636     DEBUG(Q_FUNC_INFO << ", current variable: " << STDSTRING(currentVarName));
0637 
0638 #ifdef HAVE_MATIO
0639     bool openedFile = false;
0640     if (!matfp) { // file not open
0641         matfp = Mat_Open(qPrintable(fileName), MAT_ACC_RDONLY);
0642         openedFile = true;
0643     }
0644     if (!matfp) // open failed
0645         return dataStrings << (QStringList() << i18n("File not found"));
0646 
0647     // read info and data
0648     matvar_t* var = Mat_VarReadNext(matfp); // try next first (faster)
0649     if (QLatin1String(var->name) != currentVarName)
0650         var = Mat_VarRead(matfp, qPrintable(currentVarName));
0651     // else
0652     //  DEBUG(Q_FUNC_INFO << ", was NEXT!")
0653     if (!var)
0654         return dataStrings << (QStringList() << i18n("Variable not found"));
0655     if (!var->data)
0656         return dataStrings << (QStringList() << i18n("Variable contains no data"));
0657 
0658     // DEBUG(Q_FUNC_INFO << ", start/end row = " << startRow << '/' << endRow)
0659     // DEBUG(Q_FUNC_INFO << ", start/end col = " << startColumn << '/' << endColumn)
0660 
0661     size_t actualRows = 0, actualCols = 0;
0662     int columnOffset = 0;
0663     std::vector<void*> dataContainer;
0664     QStringList vectorNames;
0665     if (var->rank == 2) { // rank is always >= 2
0666         // read data
0667         size_t rows = var->dims[0], cols = var->dims[1];
0668         if (var->class_type == MAT_C_CELL)
0669             cols = var->nbytes / var->data_size;
0670         else if (rows == 1) { // only one row: read as column
0671             rows = cols;
0672             cols = 1;
0673         }
0674         size_t actualEndRow = (endRow == -1 || endRow > (int)rows) ? rows : endRow;
0675         actualRows = actualEndRow - startRow + 1;
0676         size_t actualEndColumn = (endColumn == -1 || endColumn > (int)cols) ? cols : endColumn;
0677         actualCols = actualEndColumn - startColumn + 1;
0678         if (var->class_type == MAT_C_STRUCT) {
0679             if (endRow != -1)
0680                 actualRows = endRow - startRow + 1;
0681         } else if (var->class_type == MAT_C_CELL) { // calculated later
0682             actualEndRow = 0;
0683             actualRows = 0;
0684         }
0685         // DEBUG(Q_FUNC_INFO << ", start row = " << startRow << ", actual end row = " << actualEndRow << ", actual rows = " << actualRows)
0686         // DEBUG(Q_FUNC_INFO << ", start col = " << startColumn << ", actual end col = " << actualEndColumn << ", actual cols = " << actualCols)
0687 
0688         if (lines == 0)
0689             lines = actualRows;
0690         // double the number of cols for complex data (not for CELL or STRUCT)
0691         if (var->isComplex && var->class_type != MAT_C_CELL && var->class_type != MAT_C_STRUCT) {
0692             if (endColumn == -1) {
0693                 actualCols *= 2;
0694                 actualEndColumn *= 2;
0695             }
0696             for (size_t j = startColumn - 1; j < actualEndColumn; j++) {
0697                 if (j % 2)
0698                     vectorNames << QLatin1String("Im ") + QString::number(j / 2 + 1);
0699                 else
0700                     vectorNames << QLatin1String("Re ") + QString::number(j / 2 + 1);
0701             }
0702         }
0703 
0704         // column modes
0705         QVector<AbstractColumn::ColumnMode> columnModes;
0706         columnModes.resize(actualCols);
0707 
0708         // A: set column modes
0709         switch (var->class_type) {
0710         case MAT_C_CHAR:
0711         case MAT_C_INT8:
0712         case MAT_C_UINT8:
0713         case MAT_C_INT16:
0714         case MAT_C_UINT16:
0715         case MAT_C_INT32:
0716         case MAT_C_UINT32:
0717             for (auto& col : columnModes)
0718                 col = AbstractColumn::ColumnMode::Integer;
0719             break;
0720         case MAT_C_INT64:
0721         case MAT_C_UINT64:
0722             for (auto& col : columnModes)
0723                 col = AbstractColumn::ColumnMode::BigInt;
0724             break;
0725         case MAT_C_DOUBLE:
0726         case MAT_C_SINGLE:
0727             for (auto& col : columnModes)
0728                 col = AbstractColumn::ColumnMode::Double;
0729             break;
0730         case MAT_C_EMPTY:
0731             return dataStrings << (QStringList() << i18n("Empty"));
0732             break;
0733         case MAT_C_CELL: {
0734             DEBUG(Q_FUNC_INFO << ", found CELL. name = " << var->name << ", nbytes = " << var->nbytes << ", size = " << var->data_size)
0735             // Each element of the cell array can be a different type: one column per cell
0736             if (var->nbytes == 0 || var->data_size == 0 || var->data == nullptr)
0737                 break;
0738             // const int ncells = var->nbytes / var->data_size;
0739             // DEBUG(Q_FUNC_INFO << ", found " << ncells << " cells")
0740             columnModes.resize(actualCols);
0741 
0742             // find out number of rows
0743             for (size_t i = 0; i < actualCols; i++) {
0744                 matvar_t* cell = Mat_VarGetCell(var, i + startColumn - 1);
0745                 if (cell->rank == 2 && cell->dims[0] <= 1) { // read only rank 2 and cells with one row, omit strings
0746                     if (rows < cell->dims[1] && cell->class_type != MAT_C_CHAR) // find max row count
0747                         rows = cell->dims[1];
0748 
0749                     if (cell->name)
0750                         vectorNames << QLatin1String(cell->name);
0751                     else
0752                         vectorNames << QLatin1String("Column ") + QString::number(i + 1);
0753 
0754                     auto mode = classMode(cell->class_type);
0755                     if (dynamic_cast<Matrix*>(dataSource) && mode == AbstractColumn::ColumnMode::Text) // text not supported for matrix
0756                         mode = AbstractColumn::ColumnMode::Double;
0757 
0758                     columnModes[i] = mode;
0759                 }
0760             }
0761             // calculate from startRow and endRow
0762             actualEndRow = (endRow == -1 || endRow > (int)rows) ? rows : endRow;
0763             actualRows = actualEndRow - startRow + 1;
0764             DEBUG(Q_FUNC_INFO << ", start row = " << startRow << ", actual end row = " << actualEndRow << ", actual rows = " << actualRows)
0765             break;
0766         }
0767         case MAT_C_SPARSE:
0768             DEBUG(Q_FUNC_INFO << ", found SPARSE. name = " << var->name << ", type = " << STDSTRING(typeName(var->data_type)) << ", nbytes = " << var->nbytes
0769                               << ", size = " << var->data_size)
0770             DEBUG(Q_FUNC_INFO << ", rank " << var->rank << ", dim = " << var->dims[0] << " x " << var->dims[1])
0771 
0772             if (dataSource) {
0773                 columnModes.resize(actualCols);
0774                 auto mode = typeMode(var->data_type);
0775                 for (size_t i = 0; i < actualCols; i++)
0776                     columnModes[i] = mode;
0777             }
0778             break;
0779         case MAT_C_STRUCT: {
0780             DEBUG(Q_FUNC_INFO << ", found STRUCT. name = " << var->name << ", nbytes = " << var->nbytes << ", size = " << var->data_size)
0781             DEBUG(Q_FUNC_INFO << ", data type = " << STDSTRING(typeName(var->data_type)) << ", dims = " << var->dims[0] << " x " << var->dims[1])
0782             const int nelem = var->dims[0] * var->dims[1];
0783             const int nfields = Mat_VarGetNumberOfFields(var);
0784             DEBUG(Q_FUNC_INFO << ", nelements = " << nelem << ", nfields = " << nfields)
0785             if (endColumn == -1)
0786                 endColumn = nfields;
0787             actualCols = endColumn - startColumn + 1;
0788 
0789             if (nfields <= 0)
0790                 return dataStrings << (QStringList() << i18n("Struct contains no fields"));
0791 
0792             if (nelem < 1) {
0793                 DEBUG(Q_FUNC_INFO << ", no elements")
0794                 char* const* fieldnames = Mat_VarGetStructFieldnames(var);
0795                 if (fieldnames) {
0796                     for (int i = 0; i < nfields; i++)
0797                         DEBUG(Q_FUNC_INFO << ", field " << i << " name = " << fieldnames[i])
0798                 }
0799             }
0800 
0801             // set actualRows
0802             auto** fields = (matvar_t**)var->data;
0803             for (int i = startColumn - 1; i < std::min(nfields, endColumn); i++) {
0804                 if (fields[i]->name) {
0805                     // TODO: not needed when supporting complex column mode
0806                     if (fields[i]->isComplex)
0807                         vectorNames << QLatin1String(fields[i]->name) + QStringLiteral(" - Re") << QLatin1String(fields[i]->name) + QStringLiteral(" - Im");
0808                     else
0809                         vectorNames << QLatin1String(fields[i]->name);
0810                 } else
0811                     vectorNames << QLatin1String("Column ") + QString::number(i);
0812             }
0813             for (int i = 0; i < nfields * nelem; i++) {
0814                 const int field = i % nfields;
0815                 if (field < startColumn - 1 || field > endColumn - 1)
0816                     continue;
0817 
0818                 if (fields[i]->rank == 2) {
0819                     DEBUG(Q_FUNC_INFO << ", dims = " << fields[i]->dims[0] << " x " << fields[i]->dims[1])
0820                     size_t size;
0821                     if (fields[i]->class_type == MAT_C_CHAR) // read as string
0822                         size = fields[i]->dims[0];
0823                     else {
0824                         if (endRow == -1)
0825                             size = fields[i]->dims[0] * fields[i]->dims[1] - startRow + 1;
0826                         else
0827                             size = std::min(fields[i]->dims[0] * fields[i]->dims[1], actualRows);
0828                     }
0829 
0830                     if (actualRows < size)
0831                         actualRows = size;
0832                 } else
0833                     DEBUG(Q_FUNC_INFO << "  rank = " << fields[i]->rank)
0834 
0835                 // TODO: not needed when supporting complex column mode
0836                 if (fields[i]->isComplex) // if complex: add column
0837                     actualCols++;
0838             }
0839             DEBUG(Q_FUNC_INFO << ", Setting rows/cols to: " << actualRows << "/" << actualCols)
0840             if (dataSource) {
0841                 columnModes.resize(actualCols);
0842                 int index = 0;
0843                 for (int i = startColumn - 1; i < std::min(nfields, endColumn); i++) {
0844                     auto mode = classMode(fields[i]->class_type);
0845                     if (dynamic_cast<Matrix*>(dataSource) && mode == AbstractColumn::ColumnMode::Text) // text not supported for matrix
0846                         mode = AbstractColumn::ColumnMode::Double;
0847 
0848                     // TODO: not needed when supporting complex column mode
0849                     if (fields[i]->isComplex) // additional column for complex
0850                         columnModes[index++] = mode;
0851                     columnModes[index++] = mode;
0852                 }
0853             } else { // preview
0854                 if (actualRows > lines)
0855                     actualRows = lines;
0856 
0857                 dataStrings.resize(actualRows + 1); // + 1 for header
0858                 for (auto& string : dataStrings) {
0859                     string.reserve(actualCols);
0860                     for (size_t j = 0; j < actualCols; j++)
0861                         string << QString();
0862                 }
0863             }
0864             break;
0865         }
0866         case MAT_C_OBJECT: // not available (not supported by matio yet)
0867             DEBUG(Q_FUNC_INFO << ", found OBJECT. name = " << var->name << ", nbytes = " << var->nbytes << ", size = " << var->data_size)
0868             return dataStrings << (QStringList() << i18n("Not implemented yet"));
0869         case MAT_C_FUNCTION: // not available (not supported by matio yet)
0870             DEBUG(Q_FUNC_INFO << ", found FUNCTION. name = " << var->name << ", nbytes = " << var->nbytes << ", size = " << var->data_size)
0871             QDEBUG(Q_FUNC_INFO << ", data: " << (const char*)var->data)
0872             return dataStrings << (QStringList() << i18n("Not implemented yet"));
0873         case MAT_C_OPAQUE:
0874             return dataStrings << (QStringList() << i18n("Not implemented yet"));
0875         }
0876 
0877         // prepare import
0878         if (dataSource)
0879             columnOffset = dataSource->prepareImport(dataContainer, importMode, actualRows, actualCols, vectorNames, columnModes);
0880         DEBUG(Q_FUNC_INFO << ", column offset = " << columnOffset)
0881 
0882         // B: read data
0883         switch (var->class_type) {
0884         case MAT_C_CHAR:
0885             MAT_READ_VAR(char, int);
0886             break;
0887         case MAT_C_DOUBLE:
0888             MAT_READ_VAR(double, double);
0889             break;
0890         case MAT_C_SINGLE:
0891             MAT_READ_VAR(float, double);
0892             break;
0893         case MAT_C_INT8:
0894             MAT_READ_VAR(qint8, int);
0895             break;
0896         case MAT_C_UINT8:
0897             MAT_READ_VAR(quint8, int);
0898             break;
0899         case MAT_C_INT16:
0900             MAT_READ_VAR(qint16, int);
0901             break;
0902         case MAT_C_UINT16:
0903             MAT_READ_VAR(quint16, int);
0904             break;
0905         case MAT_C_INT32:
0906             MAT_READ_VAR(qint32, int);
0907             break;
0908         case MAT_C_UINT32:
0909             MAT_READ_VAR(quint32, int);
0910             break;
0911         case MAT_C_INT64:
0912             MAT_READ_VAR(qint64, qint64);
0913             break;
0914         case MAT_C_UINT64:
0915             MAT_READ_VAR(quint64, qint64);
0916             break;
0917         case MAT_C_EMPTY:
0918             break;
0919         case MAT_C_CELL: {
0920             if (var->nbytes == 0 || var->data_size == 0 || var->data == nullptr)
0921                 break;
0922 
0923             // TODO: complex not supported yet
0924 
0925             for (size_t i = 0; i < actualCols; i++) {
0926                 matvar_t* cell = Mat_VarGetCell(var, i + startColumn - 1);
0927                 // cell->name can be NULL
0928                 QString dims;
0929                 for (int j = 0; j < cell->rank; j++)
0930                     dims += QString::number(cell->dims[j]) + QStringLiteral(" ");
0931                 DEBUG(Q_FUNC_INFO << ", cell " << i + 1 << " : class = " << STDSTRING(className(cell->class_type))
0932                                   << ", type = " << STDSTRING(typeName(cell->data_type)) << ", rank = " << cell->rank << ", dims = " << STDSTRING(dims)
0933                                   << ", nbytes = " << cell->nbytes << ", size = " << cell->data_size)
0934             }
0935 
0936             // read cell data (see MAT_READ_VAR)
0937             for (size_t i = 0; i < actualRows; i++) {
0938                 QStringList row;
0939                 for (size_t j = 0; j < actualCols; j++) {
0940                     matvar_t* cell = Mat_VarGetCell(var, j + startColumn - 1);
0941                     const size_t cellsize = cell->dims[1];
0942                     if (cell->rank == 2 && cell->dims[0] <= 1) { // read only rank 2 and cells with zero/one row
0943                         switch (cell->class_type) {
0944                         case MAT_C_CHAR:
0945                             if (dataSource) {
0946                                 if (dynamic_cast<Matrix*>(dataSource)) {
0947                                     QDEBUG(Q_FUNC_INFO << ", WARNING: string import into matrix not supported.")
0948                                     continue;
0949                                 }
0950                                 if (i == 0) { // first line
0951                                     if (cell->data_type == MAT_T_UINT16 || cell->data_type == MAT_T_INT16) // valgrind: invalid read of size 2
0952                                         static_cast<QVector<QString>*>(dataContainer[j])->operator[](0) = QString::fromUtf16((const mat_uint16_t*)cell->data);
0953                                     else if (cell->data_type == MAT_T_UTF8)
0954                                         static_cast<QVector<QString>*>(dataContainer[j])->operator[](0) = QString::fromUtf8((const char*)cell->data);
0955                                     else
0956                                         static_cast<QVector<QString>*>(dataContainer[j])->operator[](0) = QLatin1String((const char*)cell->data);
0957                                 }
0958                             } else { // preview
0959                                 if (i == 0) { // first line
0960                                     if (cell->data_type == MAT_T_UINT16 || cell->data_type == MAT_T_INT16)
0961                                         row << QString::fromUtf16((const mat_uint16_t*)cell->data);
0962                                     else if (cell->data_type == MAT_T_UTF8)
0963                                         row << QString::fromUtf8((const char*)cell->data);
0964                                     else
0965                                         row << QLatin1String((const char*)cell->data);
0966                                 } else
0967                                     row << QString();
0968                             }
0969                             break;
0970                         case MAT_C_DOUBLE:
0971                             MAT_READ_CELL(double, double);
0972                             break;
0973                         case MAT_C_SINGLE:
0974                             MAT_READ_CELL(float, double)
0975                             break;
0976                         case MAT_C_INT8:
0977                             MAT_READ_CELL(qint8, int);
0978                             break;
0979                         case MAT_C_UINT8:
0980                             MAT_READ_CELL(quint8, int);
0981                             break;
0982                         case MAT_C_INT16:
0983                             MAT_READ_CELL(qint16, int);
0984                             break;
0985                         case MAT_C_UINT16:
0986                             MAT_READ_CELL(quint16, int);
0987                             break;
0988                         case MAT_C_INT32:
0989                             MAT_READ_CELL(qint32, int);
0990                             break;
0991                         case MAT_C_UINT32:
0992                             MAT_READ_CELL(quint32, int);
0993                             break;
0994                         case MAT_C_INT64:
0995                             MAT_READ_CELL(qint64, qint64);
0996                             break;
0997                         case MAT_C_UINT64:
0998                             MAT_READ_CELL(quint64, qint64);
0999                             break;
1000                         case MAT_C_CELL:
1001                         case MAT_C_STRUCT:
1002                         case MAT_C_OBJECT:
1003                         case MAT_C_SPARSE:
1004                         case MAT_C_FUNCTION:
1005                         case MAT_C_OPAQUE:
1006                             DEBUG(Q_FUNC_INFO << ", class type \"" << STDSTRING(className(cell->class_type)) << "\" not supported yet")
1007                             break;
1008                         case MAT_C_EMPTY:
1009                             break;
1010                         }
1011                     }
1012                 }
1013                 dataStrings << row;
1014             }
1015             break;
1016         }
1017         case MAT_C_SPARSE: {
1018             // TODO: not needed when supporting complex column mode
1019             if (var->isComplex && !dataSource) { // header for preview
1020                 QStringList row;
1021                 for (size_t j = startColumn - 1; j < actualEndColumn; j++)
1022                     if (j % 2)
1023                         row << QLatin1String("Im ") + QString::number(j / 2 + 1);
1024                     else
1025                         row << QLatin1String("Re ") + QString::number(j / 2 + 1);
1026                 dataStrings << row;
1027             }
1028 
1029             auto* sparse = (mat_sparse_t*)var->data;
1030             size_t stride = Mat_SizeOf(var->data_type);
1031             // DEBUG(Q_FUNC_INFO << ", stride = " << stride << ", njc = " << sparse->njc << ", ndata = " << sparse->ndata)
1032 
1033             switch (var->data_type) {
1034             case MAT_T_INT8:
1035                 MAT_READ_SPARSE(qint8, int)
1036                 break;
1037             case MAT_T_UINT8:
1038                 MAT_READ_SPARSE(quint8, int)
1039                 break;
1040             case MAT_T_INT16:
1041                 MAT_READ_SPARSE(qint16, int)
1042                 break;
1043             case MAT_T_UINT16:
1044                 MAT_READ_SPARSE(quint16, int)
1045                 break;
1046             case MAT_T_INT32:
1047                 MAT_READ_SPARSE(qint32, int)
1048                 break;
1049             case MAT_T_UINT32:
1050                 MAT_READ_SPARSE(quint32, int)
1051                 break;
1052             case MAT_T_INT64:
1053                 MAT_READ_SPARSE(qint64, qint64)
1054                 break;
1055             case MAT_T_UINT64:
1056                 MAT_READ_SPARSE(quint64, qint64)
1057                 break;
1058             case MAT_T_SINGLE:
1059                 MAT_READ_SPARSE(float, double)
1060                 break;
1061             case MAT_T_DOUBLE:
1062                 MAT_READ_SPARSE(double, double)
1063                 break;
1064             case MAT_T_MATRIX:
1065             case MAT_T_CELL:
1066             case MAT_T_STRUCT:
1067             case MAT_T_FUNCTION:
1068             case MAT_T_COMPRESSED:
1069             case MAT_T_UTF8:
1070             case MAT_T_UTF16:
1071             case MAT_T_UTF32:
1072             case MAT_T_STRING:
1073             case MAT_T_ARRAY:
1074             case MAT_T_UNKNOWN:
1075                 DEBUG(Q_FUNC_INFO << ", data type " << var->data_type << " not supported yet")
1076                 break;
1077             }
1078 
1079             break;
1080         }
1081         case MAT_C_STRUCT: {
1082             const int nelem = var->dims[0] * var->dims[1];
1083             const int nfields = Mat_VarGetNumberOfFields(var);
1084 
1085             if (nelem < 1) {
1086                 DEBUG(Q_FUNC_INFO << ", WARNING: nr of elements is zero")
1087                 break;
1088             }
1089 
1090             DEBUG(Q_FUNC_INFO << ", Reading data ...")
1091             auto** fields = (matvar_t**)var->data;
1092 
1093             if (!dataSource)
1094                 dataStrings[0] = vectorNames;
1095 
1096             int colIndex = 1; // count cols (only needed since complex uses two cols atm)
1097 
1098             for (int i = 0; i < nfields * nelem; i++) {
1099                 if (fields[i]->rank > 2) {
1100                     DEBUG(Q_FUNC_INFO << "  rank = " << fields[i]->rank << " not supported")
1101                     continue;
1102                 }
1103                 const int field = i % nfields;
1104                 if (field < startColumn - 1 || field > endColumn - 1)
1105                     continue;
1106                 if (field == startColumn - 1)
1107                     colIndex = 0;
1108 #ifndef NDEBUG
1109                 const int elem = i / nfields;
1110                 DEBUG(Q_FUNC_INFO << ", var " << i + 1 << "(field " << field + 1 << ", elem " << elem + 1 << "): name = " << fields[i]->name
1111                                   << ", type = " << STDSTRING(className(fields[i]->class_type)))
1112 #endif
1113                 switch (fields[i]->class_type) {
1114                 case MAT_C_INT8:
1115                     MAT_READ_STRUCT(qint8);
1116                     break;
1117                 case MAT_C_UINT8:
1118                     MAT_READ_STRUCT(quint8);
1119                     break;
1120                 case MAT_C_INT16:
1121                     MAT_READ_STRUCT(qint16);
1122                     break;
1123                 case MAT_C_UINT16:
1124                     MAT_READ_STRUCT(quint16);
1125                     break;
1126                 case MAT_C_INT32:
1127                     MAT_READ_STRUCT(qint32);
1128                     break;
1129                 case MAT_C_UINT32:
1130                     MAT_READ_STRUCT(quint32);
1131                     break;
1132                 case MAT_C_INT64:
1133                     MAT_READ_STRUCT(qint64);
1134                     break;
1135                 case MAT_C_UINT64:
1136                     MAT_READ_STRUCT(quint64);
1137                     break;
1138                 case MAT_C_SINGLE:
1139                     MAT_READ_STRUCT(float);
1140                     break;
1141                 case MAT_C_DOUBLE:
1142                     MAT_READ_STRUCT(double);
1143                     break;
1144                 case MAT_C_CHAR:
1145                     if (dynamic_cast<Matrix*>(dataSource)) {
1146                         QDEBUG(Q_FUNC_INFO << ", WARNING: string import into matrix not supported.")
1147                         break;
1148                     }
1149 
1150                     if (fields[i]->rank == 2)
1151                         DEBUG(Q_FUNC_INFO << "  rank = 2 (" << fields[i]->dims[0] << " x " << fields[i]->dims[1] << ")")
1152                     else
1153                         DEBUG(Q_FUNC_INFO << "  rank = " << fields[i]->rank)
1154 
1155                     if (fields[i]->data_type == MAT_T_UINT16 || fields[i]->data_type == MAT_T_INT16) {
1156                         auto* data = (mat_uint16_t*)fields[i]->data;
1157 
1158                         QString s = QString::fromUtf16(data);
1159                         DEBUG(Q_FUNC_INFO << ", UTF16 data: \"" << STDSTRING(s) << "\"")
1160                         // TODO: row
1161                         if (dataSource)
1162                             (*static_cast<QVector<QString>*>(dataContainer[colIndex]))[0] = s;
1163                         else
1164                             dataStrings[1][colIndex] = s;
1165                     } else {
1166                         char* data = (char*)fields[i]->data;
1167                         if (fields[i]->data_type == MAT_T_UTF8) {
1168                             QString s;
1169                             if (fields[i]->rank == 2)
1170                                 s = QString::fromUtf8(data, fields[i]->dims[1]);
1171                             else
1172                                 s = QString::fromUtf8(data);
1173                             DEBUG(Q_FUNC_INFO << ", UTF8 data: \"" << STDSTRING(s) << "\"")
1174                             // TODO: row
1175                             if (dataSource)
1176                                 (*static_cast<QVector<QString>*>(dataContainer[colIndex]))[0] = s;
1177                             else
1178                                 dataStrings[1][colIndex] = s;
1179                         } else {
1180                             DEBUG(Q_FUNC_INFO << ", STRING data: \"" << STDSTRING(QString::fromLatin1(data)) << "\"")
1181                             // TODO: row
1182                             if (dataSource)
1183                                 (*static_cast<QVector<QString>*>(dataContainer[colIndex]))[0] = QLatin1String(data);
1184                             else
1185                                 dataStrings[1][colIndex] = QLatin1String(data);
1186                         }
1187                     }
1188                     break;
1189                 case MAT_C_CELL:
1190                 case MAT_C_STRUCT:
1191                 case MAT_C_OBJECT:
1192                 case MAT_C_SPARSE:
1193                 case MAT_C_FUNCTION:
1194                 case MAT_C_OPAQUE:
1195                     DEBUG(Q_FUNC_INFO << ", not support struct field class type " << STDSTRING(className(fields[i]->class_type)))
1196                     break;
1197                 case MAT_C_EMPTY:
1198                     break;
1199                 }
1200 
1201                 colIndex++;
1202             }
1203             break;
1204         }
1205         case MAT_C_OBJECT: // unsupported (s.a.)
1206         case MAT_C_FUNCTION: // unsupported (s.a.)
1207         case MAT_C_OPAQUE: // ???
1208             break;
1209         }
1210     }
1211     if (var->rank > 2) // TODO
1212         return dataStrings << (QStringList() << i18n("Not implemented yet"));
1213 
1214     Mat_VarFree(var);
1215     if (openedFile) {
1216         Mat_Close(matfp);
1217         matfp = nullptr;
1218     }
1219 
1220     if (dataSource)
1221         dataSource->finalizeImport(columnOffset, 1, actualCols, QString(), importMode);
1222 #else
1223     Q_UNUSED(fileName)
1224     Q_UNUSED(dataSource)
1225     Q_UNUSED(importMode)
1226     Q_UNUSED(lines)
1227 #endif
1228 
1229     return dataStrings;
1230 }
1231 
1232 /*!
1233     writes the content of \c dataSource to the file \c fileName.
1234 */
1235 void MatioFilterPrivate::write(const QString& /*fileName*/, AbstractDataSource* /*dataSource*/) {
1236     // TODO: writing MAT files not implemented yet
1237 }
1238 
1239 // ##############################################################################
1240 // ##################  Serialization/Deserialization  ###########################
1241 // ##############################################################################
1242 
1243 /*!
1244   Saves as XML.
1245  */
1246 void MatioFilter::save(QXmlStreamWriter* writer) const {
1247     writer->writeStartElement(QStringLiteral("matioFilter"));
1248     writer->writeEndElement();
1249 }
1250 
1251 /*!
1252   Loads from XML.
1253 */
1254 bool MatioFilter::load(XmlStreamReader*) {
1255     return true;
1256 }