File indexing completed on 2024-12-22 03:35:45

0001 /*
0002     File                 : HDF5Filter.cpp
0003     Project              : LabPlot
0004     Description          : HDF5 I/O-filter
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2015-2022 Stefan Gerlach <stefan.gerlach@uni.kn>
0007     SPDX-FileCopyrightText: 2017 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 /* TODO:
0012  * Feature: implement missing data types and ranks
0013  * Performance: only fill dataPointer or dataStrings (not both)
0014  */
0015 
0016 #include "backend/datasources/filters/HDF5Filter.h"
0017 #include "backend/core/column/Column.h"
0018 #include "backend/datasources/LiveDataSource.h"
0019 #include "backend/datasources/filters/HDF5FilterPrivate.h"
0020 #include "backend/lib/XmlStreamReader.h"
0021 #include "backend/lib/macros.h"
0022 
0023 #include <KLocalizedString>
0024 #include <QFile>
0025 #include <QProcess>
0026 #include <QStandardPaths>
0027 #include <QTreeWidgetItem>
0028 
0029 ///////////// macros ///////////////////////////////////////////////
0030 // type - data type
0031 #define HDF5_READ_1D(type)                                                                                                                                     \
0032     {                                                                                                                                                          \
0033         for (int i = startRow - 1; i < std::min(endRow, lines + startRow - 1); ++i) {                                                                          \
0034             if (dataContainer)                                                                                                                                 \
0035                 (*static_cast<QVector<type>*>(dataContainer))[i - startRow + 1] = data[i];                                                                     \
0036             else /* for preview */                                                                                                                             \
0037                 dataString << QString::number(static_cast<type>(data[i]));                                                                                     \
0038         }                                                                                                                                                      \
0039     }
0040 // type - data type, ctype - container type
0041 #define HDF5_READ_VLEN_1D(type, ctype)                                                                                                                         \
0042     {                                                                                                                                                          \
0043         auto* data = (type*)rdata[c].p;                                                                                                                        \
0044         for (int i = startRow - 1; i < std::min(length, lines + startRow - 1); ++i) {                                                                          \
0045             if (dataSource)                                                                                                                                    \
0046                 (*static_cast<QVector<ctype>*>(dataContainer[c - startColumn + 1]))[i - startRow + 1] = data[i];                                               \
0047             else /* for preview */                                                                                                                             \
0048                 dataStrings[i - startRow + 1] << QString::number(static_cast<type>(data[i]));                                                                  \
0049         }                                                                                                                                                      \
0050         /* fill columns until maxLength */                                                                                                                     \
0051         if (!dataSource)                                                                                                                                       \
0052             for (int i = std::min(length, lines + startRow - 1); i < std::min(endRow, lines + startRow - 1); i++) {                                            \
0053                 dataStrings[i - startRow + 1] << QString();                                                                                                    \
0054             }                                                                                                                                                  \
0055     }
0056 
0057 // type - data type
0058 #define HDF5_READ_2D(type)                                                                                                                                     \
0059     {                                                                                                                                                          \
0060         for (int i = startRow - 1; i < std::min(endRow, lines + startRow - 1); ++i) {                                                                          \
0061             QStringList line;                                                                                                                                  \
0062             line.reserve(endColumn - startColumn + 1);                                                                                                         \
0063             for (int j = startColumn - 1; j < endColumn; ++j) {                                                                                                \
0064                 if (dataPointer[0])                                                                                                                            \
0065                     (*static_cast<QVector<type>*>(dataPointer[j - startColumn + 1]))[i - startRow + 1] = data[i][j];                                           \
0066                 else                                                                                                                                           \
0067                     line << QString::number(static_cast<type>(data[i][j]));                                                                                    \
0068             }                                                                                                                                                  \
0069             dataStrings << line;                                                                                                                               \
0070         }                                                                                                                                                      \
0071     }
0072 
0073 //////////////////////////////////////////////////////////////////////
0074 
0075 /*!
0076     \class HDF5Filter
0077     \brief Manages the import/export of data from/to a HDF5 file.
0078 
0079     \ingroup datasources
0080 */
0081 HDF5Filter::HDF5Filter()
0082     : AbstractFileFilter(FileType::HDF5)
0083     , d(new HDF5FilterPrivate(this)) {
0084 }
0085 
0086 HDF5Filter::~HDF5Filter() = default;
0087 
0088 /*!
0089   parses the content of the file \c fileName.
0090 */
0091 int HDF5Filter::parse(const QString& fileName, QTreeWidgetItem* rootItem) {
0092     return d->parse(fileName, rootItem);
0093 }
0094 
0095 /*!
0096   reads the content of the data set \c dataSet from file \c fileName.
0097 */
0098 QVector<QStringList>
0099 HDF5Filter::readCurrentDataSet(const QString& fileName, AbstractDataSource* dataSource, bool& ok, AbstractFileFilter::ImportMode importMode, int lines) {
0100     return d->readCurrentDataSet(fileName, dataSource, ok, importMode, lines);
0101 }
0102 
0103 /*!
0104   reads the content of the file \c fileName to the data source \c dataSource.
0105 */
0106 void HDF5Filter::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode) {
0107     d->readDataFromFile(fileName, dataSource, mode);
0108 }
0109 
0110 /*!
0111 writes the content of the data source \c dataSource to the file \c fileName.
0112 */
0113 void HDF5Filter::write(const QString& fileName, AbstractDataSource* dataSource) {
0114     d->write(fileName, dataSource);
0115 }
0116 
0117 ///////////////////////////////////////////////////////////////////////
0118 
0119 void HDF5Filter::setCurrentDataSetName(const QString& ds) {
0120     DEBUG(Q_FUNC_INFO << ", name = " << STDSTRING(ds))
0121     d->currentDataSetName = ds;
0122 }
0123 
0124 const QString HDF5Filter::currentDataSetName() const {
0125     return d->currentDataSetName;
0126 }
0127 
0128 void HDF5Filter::setStartRow(const int s) {
0129     d->startRow = s;
0130 }
0131 
0132 int HDF5Filter::startRow() const {
0133     return d->startRow;
0134 }
0135 
0136 void HDF5Filter::setEndRow(const int e) {
0137     d->endRow = e;
0138 }
0139 
0140 int HDF5Filter::endRow() const {
0141     return d->endRow;
0142 }
0143 
0144 void HDF5Filter::setStartColumn(const int c) {
0145     d->startColumn = c;
0146 }
0147 
0148 int HDF5Filter::startColumn() const {
0149     return d->startColumn;
0150 }
0151 
0152 void HDF5Filter::setEndColumn(const int c) {
0153     d->endColumn = c;
0154 }
0155 
0156 int HDF5Filter::endColumn() const {
0157     return d->endColumn;
0158 }
0159 
0160 QString HDF5Filter::fileInfoString(const QString& fileName) {
0161     DEBUG(Q_FUNC_INFO);
0162     QString info;
0163 #ifdef HAVE_HDF5
0164     DEBUG(Q_FUNC_INFO << ", fileName = " << qPrintable(fileName));
0165 
0166     // check file type first
0167     htri_t isHdf5 = H5Fis_hdf5(qPrintable(fileName));
0168     if (isHdf5 == 0) {
0169         DEBUG(qPrintable(fileName) << " is not a HDF5 file! isHdf5 = " << isHdf5 << " Giving up.");
0170         return i18n("Not a HDF5 file");
0171     }
0172     if (isHdf5 < 0) {
0173         DEBUG("H5Fis_hdf5() failed on " << qPrintable(fileName) << "! Giving up.");
0174         return i18n("Failed checking file");
0175     }
0176 
0177     // open file
0178     hid_t file = H5Fopen(qPrintable(fileName), H5F_ACC_RDONLY, H5P_DEFAULT);
0179     HDF5FilterPrivate::handleError((int)file, QStringLiteral("H5Fopen"), fileName);
0180     if (file < 0) {
0181         DEBUG("Opening file " << qPrintable(fileName) << " failed! Giving up.");
0182         return i18n("Failed opening HDF5 file");
0183     }
0184 
0185     hsize_t size;
0186     herr_t status = H5Fget_filesize(file, &size);
0187     if (status >= 0) {
0188         info += i18n("File size: %1 bytes", QString::number(size));
0189         info += QLatin1String("<br>");
0190     }
0191 
0192     hssize_t freesize = H5Fget_freespace(file);
0193     info += i18n("Free space: %1 bytes", QString::number(freesize));
0194     info += QLatin1String("<br>");
0195     info += QLatin1String("<br>");
0196 
0197     ssize_t objectCount;
0198     objectCount = H5Fget_obj_count(file, H5F_OBJ_FILE);
0199     info += i18n("Number of files: %1", QString::number(objectCount));
0200     info += QLatin1String("<br>");
0201     objectCount = H5Fget_obj_count(file, H5F_OBJ_DATASET);
0202     info += i18n("Number of data sets: %1", QString::number(objectCount));
0203     info += QLatin1String("<br>");
0204     objectCount = H5Fget_obj_count(file, H5F_OBJ_GROUP);
0205     info += i18n("Number of groups: %1", QString::number(objectCount));
0206     info += QLatin1String("<br>");
0207     objectCount = H5Fget_obj_count(file, H5F_OBJ_DATATYPE);
0208     info += i18n("Number of named datatypes: %1", QString::number(objectCount));
0209     info += QLatin1String("<br>");
0210     objectCount = H5Fget_obj_count(file, H5F_OBJ_ATTR);
0211     info += i18n("Number of attributes: %1", QString::number(objectCount));
0212     info += QLatin1String("<br>");
0213     objectCount = H5Fget_obj_count(file, H5F_OBJ_ALL);
0214     info += i18n("Number of all objects: %1", QString::number(objectCount));
0215     info += QLatin1String("<br>");
0216 
0217 #ifdef HAVE_AT_LEAST_HDF5_1_10_0 // using H5Fget_info2 struct (see H5Fpublic.h)
0218     H5F_info2_t file_info;
0219     status = H5Fget_info2(file, &file_info);
0220     if (status >= 0) {
0221         info += QLatin1String("<br>");
0222         info += i18n("Version of superblock: %1", QString::number(file_info.super.version));
0223         info += QLatin1String("<br>");
0224         info += i18n("Size of superblock: %1 bytes", QString::number(file_info.super.super_size));
0225         info += QLatin1String("<br>");
0226         info += i18n("Size of superblock extension: %1 bytes", QString::number(file_info.super.super_ext_size));
0227         info += QLatin1String("<br>");
0228         info += i18n("Version of free-space manager: %1", QString::number(file_info.free.version));
0229         info += QLatin1String("<br>");
0230         info += i18n("Size of free-space manager metadata: %1 bytes", QString::number(file_info.free.meta_size));
0231         info += QLatin1String("<br>");
0232         info += i18n("Total size of free space: %1 bytes", QString::number(file_info.free.tot_space));
0233         info += QLatin1String("<br>");
0234         info += i18n("Version of shared object header: %1", QString::number(file_info.sohm.version));
0235         info += QLatin1String("<br>");
0236         info += i18n("Size of shared object header: %1 bytes", QString::number(file_info.sohm.hdr_size));
0237         info += QLatin1String("<br>");
0238         info += i18n("Size of all shared object header indexes: %1 bytes", QString::number(file_info.sohm.msgs_info.index_size));
0239         info += QLatin1String("<br>");
0240         info += i18n("Size of the heap: %1 bytes", QString::number(file_info.sohm.msgs_info.heap_size));
0241         info += QLatin1String("<br>");
0242     }
0243 #else // using H5Fget_info1 struct (named H5F_info_t in HDF5 1.8)
0244     H5F_info_t file_info;
0245     status = H5Fget_info(file, &file_info);
0246     if (status >= 0) {
0247         info += i18n("Size of superblock extension: %1 bytes", QString::number(file_info.super_ext_size));
0248         info += QLatin1String("<br>");
0249         info += i18n("Size of shared object header: %1 bytes", QString::number(file_info.sohm.hdr_size));
0250         info += QLatin1String("<br>");
0251         info += i18n("Size of all shared object header indexes: %1 bytes", QString::number(file_info.sohm.msgs_info.index_size));
0252         info += QLatin1String("<br>");
0253         info += i18n("Size of the heap: %1 bytes", QString::number(file_info.sohm.msgs_info.heap_size));
0254         info += QLatin1String("<br>");
0255     }
0256 #endif
0257 
0258     // cache information
0259     // see https://support.hdfgroup.org/HDF5/doc/RM/RM_H5F.html
0260     info += QLatin1String("<br>");
0261     H5AC_cache_config_t config;
0262     config.version = H5AC__CURR_CACHE_CONFIG_VERSION;
0263     status = H5Fget_mdc_config(file, &config);
0264     if (status >= 0) {
0265         info += i18n("Cache config version: %1", QString::number(config.version));
0266         info += QLatin1String("<br>");
0267         info += i18n("Adaptive cache resize report function enabled: %1", config.rpt_fcn_enabled ? i18n("Yes") : i18n("No"));
0268         info += QLatin1String("<br>");
0269         info += i18n("Cache initial maximum size: %1 bytes", QString::number(config.initial_size));
0270         info += QLatin1String("<br>");
0271         info += i18n("Adaptive cache maximum size: %1 bytes", QString::number(config.max_size));
0272         info += QLatin1String("<br>");
0273         info += i18n("Adaptive cache minimum size: %1 bytes", QString::number(config.min_size));
0274         info += QLatin1String("<br>");
0275         // TODO: more settings
0276     }
0277     double hit_rate;
0278     status = H5Fget_mdc_hit_rate(file, &hit_rate);
0279     info += i18n("Metadata cache hit rate: %1", QString::number(hit_rate));
0280     info += QLatin1String("<br>");
0281     // TODO: herr_t H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr, hsize_t *image_len)
0282     size_t max_size, min_clean_size, cur_size;
0283     int cur_num_entries;
0284     status = H5Fget_mdc_size(file, &max_size, &min_clean_size, &cur_size, &cur_num_entries);
0285     if (status >= 0) {
0286         info += i18n("Current cache maximum size: %1 bytes", QString::number(max_size));
0287         info += QLatin1String("<br>");
0288         info += i18n("Current cache minimum clean size: %1 bytes", QString::number(min_clean_size));
0289         info += QLatin1String("<br>");
0290         info += i18n("Current cache size: %1 bytes", QString::number(cur_size));
0291         info += QLatin1String("<br>");
0292         info += i18n("Current number of entries in the cache: %1", QString::number(cur_num_entries));
0293         info += QLatin1String("<br>");
0294     }
0295     // TODO: 1.10 herr_t H5Fget_metadata_read_retry_info( hid_t file_id, H5F_retry_info_t *info )
0296     /* TODO: not available
0297     hbool_t atomicMode;
0298     status = H5Fget_mpi_atomicity(file, &atomicMode);
0299     if (status >= 0) {
0300         info += i18n("MPI file access atomic mode: %1", atomicMode ? i18n("Yes") : i18n("No"));
0301         info += QLatin1String("<br>");
0302     }*/
0303 #ifdef HAVE_AT_LEAST_HDF5_1_10_0
0304     hbool_t is_enabled, is_currently_logging;
0305     status = H5Fget_mdc_logging_status(file, &is_enabled, &is_currently_logging);
0306     if (status >= 0) {
0307         info += i18n("Logging enabled: %1", is_enabled ? i18n("Yes") : i18n("No"));
0308         info += QLatin1String("<br>");
0309         info += i18n("Events are currently logged: %1", is_currently_logging ? i18n("Yes") : i18n("No"));
0310         info += QLatin1String("<br>");
0311     }
0312 #endif
0313 #ifdef HAVE_AT_LEAST_HDF5_1_10_1
0314     unsigned int accesses[2], hits[2], misses[2], evictions[2], bypasses[2];
0315     status = H5Fget_page_buffering_stats(file, accesses, hits, misses, evictions, bypasses);
0316     if (status >= 0) {
0317         info += i18n("Metadata/raw data page buffer accesses: %1 %2", QString::number(accesses[0]), QString::number(accesses[1]));
0318         info += QLatin1String("<br>");
0319         info += i18n("Metadata/raw data page buffer hits: %1 %2", QString::number(hits[0]), QString::number(hits[1]));
0320         info += QLatin1String("<br>");
0321         info += i18n("Metadata/raw data page buffer misses: %1 %2", QString::number(misses[0]), QString::number(misses[1]));
0322         info += QLatin1String("<br>");
0323         info += i18n("Metadata/raw data page buffer evictions: %1 %2", QString::number(evictions[0]), QString::number(evictions[1]));
0324         info += QLatin1String("<br>");
0325         info += i18n("Metadata/raw data accesses bypassing page buffer: %1 %2", QString::number(bypasses[0]), QString::number(bypasses[1]));
0326         info += QLatin1String("<br>");
0327     } else {
0328         info += i18n("Page buffer disabled");
0329         info += QLatin1String("<br>");
0330         DEBUG("H5Fget_page_buffering_stats() status = " << status);
0331     }
0332 #endif
0333 #else
0334     Q_UNUSED(fileName);
0335 #endif
0336     return info;
0337 }
0338 
0339 /*!
0340  * Get file content in DDL (Data Description Language) format
0341  * uses "h5dump"
0342  */
0343 QString HDF5Filter::fileDDLString(const QString& fileName) {
0344     DEBUG(Q_FUNC_INFO);
0345 
0346     QString DDLString;
0347 #ifdef Q_OS_LINUX
0348     const QString h5dumpFullPath = QStandardPaths::findExecutable(QLatin1String("h5dump"));
0349     if (h5dumpFullPath.isEmpty())
0350         return i18n("h5dump not found.");
0351 
0352     QProcess proc;
0353     QStringList args;
0354     args << QStringLiteral("-H") << fileName;
0355     proc.start(h5dumpFullPath, args);
0356 
0357     if (proc.waitForReadyRead(1000) == false)
0358         DDLString += i18n("Reading from file %1 failed.", fileName);
0359     else {
0360         DDLString += QLatin1String(proc.readAll());
0361         DDLString.replace(QLatin1Char('\n'), QLatin1String("<br>\n"));
0362         DDLString.replace(QLatin1Char('\t'), QLatin1String("&nbsp;&nbsp;&nbsp;&nbsp;"));
0363         // DEBUG("  DDL string: " << STDSTRING(DDLString));
0364     }
0365 #else // TODO: h5dump on Win, Mac
0366     Q_UNUSED(fileName)
0367 #endif
0368 
0369     return DDLString;
0370 }
0371 
0372 // #####################################################################
0373 // ################### Private implementation ##########################
0374 // #####################################################################
0375 
0376 HDF5FilterPrivate::HDF5FilterPrivate(HDF5Filter* owner)
0377     : q(owner) {
0378 #ifdef HAVE_HDF5
0379     m_status = 0;
0380 #endif
0381 }
0382 
0383 #ifdef HAVE_HDF5
0384 void HDF5FilterPrivate::handleError(int err, const QString& function, const QString& arg) {
0385 #ifdef NDEBUG
0386     Q_UNUSED(err)
0387     Q_UNUSED(function)
0388     Q_UNUSED(arg)
0389 #else
0390     if (err < 0) {
0391         DEBUG("ERROR " << err << ": " << STDSTRING(function) << "() - " << STDSTRING(arg));
0392     }
0393 #endif
0394 }
0395 
0396 QString HDF5FilterPrivate::translateHDF5Order(H5T_order_t o) {
0397     QString order;
0398     switch (o) {
0399     case H5T_ORDER_LE:
0400         order = QStringLiteral("LE");
0401         break;
0402     case H5T_ORDER_BE:
0403         order = QStringLiteral("BE");
0404         break;
0405     case H5T_ORDER_VAX:
0406         order = QStringLiteral("VAX");
0407         break;
0408     case H5T_ORDER_MIXED:
0409         order = QStringLiteral("MIXED");
0410         break;
0411     case H5T_ORDER_NONE:
0412         order = QStringLiteral("NONE");
0413         break;
0414     case H5T_ORDER_ERROR:
0415         order = QStringLiteral("ERROR");
0416         break;
0417     }
0418 
0419     return order;
0420 }
0421 
0422 QString HDF5FilterPrivate::translateHDF5Type(hid_t t) {
0423     QString type;
0424 
0425     if (H5Tequal(t, H5T_STD_I8LE) || H5Tequal(t, H5T_STD_I8BE))
0426         type = QStringLiteral("CHAR");
0427     else if (H5Tequal(t, H5T_STD_U8LE) || H5Tequal(t, H5T_STD_U8BE))
0428         type = QStringLiteral("UCHAR");
0429     else if (H5Tequal(t, H5T_STD_I16LE) || H5Tequal(t, H5T_STD_I16BE))
0430         type = QStringLiteral("SHORT");
0431     else if (H5Tequal(t, H5T_STD_U16LE) || H5Tequal(t, H5T_STD_U16BE))
0432         type = QStringLiteral("USHORT");
0433     else if (H5Tequal(t, H5T_STD_I32LE) || H5Tequal(t, H5T_STD_I32BE))
0434         type = QStringLiteral("INT");
0435     else if (H5Tequal(t, H5T_STD_U32LE) || H5Tequal(t, H5T_STD_U32BE))
0436         type = QStringLiteral("UINT");
0437     else if (H5Tequal(t, H5T_NATIVE_LONG))
0438         type = QStringLiteral("LONG");
0439     else if (H5Tequal(t, H5T_NATIVE_ULONG))
0440         type = QStringLiteral("ULONG");
0441     else if (H5Tequal(t, H5T_STD_I64LE) || H5Tequal(t, H5T_STD_I64BE))
0442         type = QStringLiteral("LLONG");
0443     else if (H5Tequal(t, H5T_STD_U64LE) || H5Tequal(t, H5T_STD_U64BE))
0444         type = QStringLiteral("ULLONG");
0445     else if (H5Tequal(t, H5T_IEEE_F32LE) || H5Tequal(t, H5T_IEEE_F32BE))
0446         type = QStringLiteral("FLOAT");
0447     else if (H5Tequal(t, H5T_IEEE_F64LE) || H5Tequal(t, H5T_IEEE_F64BE))
0448         type = QStringLiteral("DOUBLE");
0449     else if (H5Tequal(t, H5T_NATIVE_LDOUBLE))
0450         type = QStringLiteral("LDOUBLE");
0451     else
0452         type = QStringLiteral("UNKNOWN");
0453 
0454     return type;
0455 }
0456 
0457 QString HDF5FilterPrivate::translateHDF5Class(H5T_class_t c) {
0458     QString dclass;
0459     switch (c) {
0460     case H5T_INTEGER:
0461         dclass = QStringLiteral("INTEGER");
0462         break;
0463     case H5T_FLOAT:
0464         dclass = QStringLiteral("FLOAT");
0465         break;
0466     case H5T_STRING:
0467         dclass = QStringLiteral("STRING");
0468         break;
0469     case H5T_BITFIELD:
0470         dclass = QStringLiteral("BITFIELD");
0471         break;
0472     case H5T_OPAQUE:
0473         dclass = QStringLiteral("OPAQUE");
0474         break;
0475     case H5T_COMPOUND:
0476         dclass = QStringLiteral("COMPOUND");
0477         break;
0478     case H5T_ARRAY:
0479         dclass = QStringLiteral("ARRAY");
0480         break;
0481     case H5T_ENUM:
0482         dclass = QStringLiteral("ENUM");
0483         break;
0484     case H5T_REFERENCE:
0485         dclass = QStringLiteral("REFERENCE");
0486         break;
0487     case H5T_VLEN:
0488         dclass = QStringLiteral("VLEN");
0489         break;
0490     case H5T_TIME:
0491         dclass = QStringLiteral("TIME");
0492         break;
0493     case H5T_NCLASSES:
0494         dclass = QStringLiteral("NCLASSES");
0495         break;
0496     case H5T_NO_CLASS:
0497         dclass = QStringLiteral("NOCLASS");
0498         break;
0499     }
0500     return dclass;
0501 }
0502 
0503 AbstractColumn::ColumnMode HDF5FilterPrivate::translateHDF5TypeToMode(hid_t t) {
0504     if (H5Tequal(t, H5T_STD_U32LE) || H5Tequal(t, H5T_STD_U32BE) || H5Tequal(t, H5T_NATIVE_LONG) || H5Tequal(t, H5T_NATIVE_ULONG) || H5Tequal(t, H5T_STD_I64LE)
0505         || H5Tequal(t, H5T_STD_I64BE) || H5Tequal(t, H5T_STD_U64LE) || H5Tequal(t, H5T_STD_U64BE))
0506         return AbstractColumn::ColumnMode::BigInt;
0507 
0508     if (H5Tequal(t, H5T_IEEE_F32LE) || H5Tequal(t, H5T_IEEE_F32BE) || H5Tequal(t, H5T_IEEE_F64LE) || H5Tequal(t, H5T_IEEE_F64BE)
0509         || H5Tequal(t, H5T_NATIVE_LDOUBLE))
0510         return AbstractColumn::ColumnMode::Double;
0511 
0512     // everything else
0513     return AbstractColumn::ColumnMode::Integer;
0514 }
0515 
0516 QStringList HDF5FilterPrivate::readHDF5Compound(hid_t tid) {
0517     size_t typeSize = H5Tget_size(tid);
0518 
0519     QString line;
0520     line += QLatin1String("COMPOUND(") + QString::number(typeSize) + QLatin1String(") : (");
0521     int members = H5Tget_nmembers(tid);
0522     handleError(members, QStringLiteral("H5Tget_nmembers"));
0523     for (int i = 0; i < members; ++i) {
0524         H5T_class_t mclass = H5Tget_member_class(tid, i);
0525         handleError((int)mclass, QStringLiteral("H5Tget_member_class"));
0526         hid_t mtype = H5Tget_member_type(tid, i);
0527         handleError((int)mtype, QStringLiteral("H5Tget_member_type"));
0528         size_t size = H5Tget_size(mtype);
0529         handleError((int)size, QStringLiteral("H5Tget_size"));
0530         QString typeString = translateHDF5Class(mclass);
0531         if (mclass == H5T_INTEGER || mclass == H5T_FLOAT)
0532             typeString = translateHDF5Type(mtype);
0533         line +=
0534             QLatin1String(H5Tget_member_name(tid, i)) + QStringLiteral("[") + typeString + QStringLiteral("(") + QString::number(size) + QStringLiteral(")]");
0535         if (i == members - 1)
0536             line += QLatin1String(")");
0537         else
0538             line += QLatin1String(",");
0539         m_status = H5Tclose(mtype);
0540         handleError(m_status, QStringLiteral("H5Tclose"));
0541     }
0542 
0543     QStringList dataString;
0544     dataString << line;
0545 
0546     return dataString;
0547 }
0548 
0549 template<typename T>
0550 QStringList HDF5FilterPrivate::readHDF5Data1D(hid_t dataset, hid_t dtype, int rows, int lines, void* dataContainer) {
0551     DEBUG(Q_FUNC_INFO << ", rows = " << rows << ", lines = " << lines);
0552     QStringList dataString;
0553 
0554     // we read all rows of data
0555     T* data = new T[rows];
0556 
0557     m_status = H5Dread(dataset, dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
0558     handleError(m_status, QStringLiteral("H5Dread"));
0559     DEBUG(Q_FUNC_INFO << ", startRow = " << startRow << ", endRow = " << endRow);
0560     DEBUG(Q_FUNC_INFO << ", dataContainer = " << dataContainer);
0561 
0562     H5T_class_t dclass = H5Tget_class(dtype);
0563     handleError((int)dclass, QStringLiteral("H5Dget_class"));
0564     if (dclass == H5T_INTEGER) {
0565         if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG) || H5Tequal(dtype, H5T_STD_U64LE)
0566             || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG)) {
0567             HDF5_READ_1D(qint64);
0568         } else
0569             HDF5_READ_1D(int);
0570     } else
0571         HDF5_READ_1D(double);
0572 
0573     delete[] data;
0574 
0575     return dataString;
0576 }
0577 
0578 QStringList HDF5FilterPrivate::readHDF5CompoundData1D(hid_t dataset, hid_t tid, int rows, int lines, std::vector<void*>& dataContainer) {
0579     DEBUG(Q_FUNC_INFO << ", data container size = " << dataContainer.size());
0580     int members = H5Tget_nmembers(tid);
0581     bool preview = !dataContainer[0];
0582     handleError(members, QStringLiteral("H5Tget_nmembers"));
0583     // DEBUG(" # members = " << members);
0584 
0585     QStringList dataString;
0586     if (preview) {
0587         for (int i = 0; i < std::min(rows, lines); ++i)
0588             dataString << QStringLiteral("(");
0589         dataContainer.resize(members); // avoid "index out of range" for preview
0590     }
0591 
0592     for (int m = 0; m < members; ++m) {
0593         // DEBUG(Q_FUNC_INFO << ", member " << m)
0594         hid_t mtype = H5Tget_member_type(tid, m);
0595         handleError((int)mtype, QStringLiteral("H5Tget_member_type"));
0596         size_t msize = H5Tget_size(mtype);
0597         handleError((int)msize, QStringLiteral("H5Tget_size"));
0598         hid_t ctype = H5Tcreate(H5T_COMPOUND, msize);
0599         handleError((int)ctype, QStringLiteral("H5Tcreate"));
0600         m_status = H5Tinsert(ctype, H5Tget_member_name(tid, m), 0, mtype);
0601         handleError(m_status, QStringLiteral("H5Tinsert"));
0602 
0603         QStringList mdataString;
0604         if (H5Tequal(mtype, H5T_STD_I8LE) || H5Tequal(mtype, H5T_STD_I8BE))
0605             mdataString = readHDF5Data1D<qint8>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0606         else if (H5Tequal(mtype, H5T_NATIVE_CHAR)) {
0607             switch (sizeof(H5T_NATIVE_CHAR)) {
0608             case 1:
0609                 mdataString = readHDF5Data1D<qint8>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0610                 break;
0611             case 2:
0612                 mdataString = readHDF5Data1D<qint16>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0613                 break;
0614             case 4:
0615                 mdataString = readHDF5Data1D<qint32>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0616                 break;
0617             case 8:
0618                 mdataString = readHDF5Data1D<qint64>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0619                 break;
0620             }
0621         } else if (H5Tequal(mtype, H5T_STD_U8LE) || H5Tequal(mtype, H5T_STD_U8BE))
0622             mdataString = readHDF5Data1D<uint8_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0623         else if (H5Tequal(mtype, H5T_NATIVE_UCHAR)) {
0624             switch (sizeof(H5T_NATIVE_UCHAR)) {
0625             case 1:
0626                 mdataString = readHDF5Data1D<uint8_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0627                 break;
0628             case 2:
0629                 mdataString = readHDF5Data1D<uint16_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0630                 break;
0631             case 4:
0632                 mdataString = readHDF5Data1D<uint32_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0633                 break;
0634             case 8:
0635                 mdataString = readHDF5Data1D<uint64_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0636                 break;
0637             }
0638         } else if (H5Tequal(mtype, H5T_STD_I16LE) || H5Tequal(mtype, H5T_STD_I16BE) || H5Tequal(mtype, H5T_NATIVE_SHORT))
0639             mdataString = readHDF5Data1D<short>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0640         else if (H5Tequal(mtype, H5T_STD_U16LE) || H5Tequal(mtype, H5T_STD_U16BE) || H5Tequal(mtype, H5T_NATIVE_SHORT))
0641             mdataString = readHDF5Data1D<unsigned short>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0642         else if (H5Tequal(mtype, H5T_STD_I32LE) || H5Tequal(mtype, H5T_STD_I32BE) || H5Tequal(mtype, H5T_NATIVE_INT))
0643             mdataString = readHDF5Data1D<int>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0644         else if (H5Tequal(mtype, H5T_STD_U32LE) || H5Tequal(mtype, H5T_STD_U32BE) || H5Tequal(mtype, H5T_NATIVE_UINT))
0645             mdataString = readHDF5Data1D<unsigned int>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0646         else if (H5Tequal(mtype, H5T_NATIVE_LONG))
0647             mdataString = readHDF5Data1D<long>(dataset, ctype, rows, lines, dataContainer[m]);
0648         else if (H5Tequal(mtype, H5T_NATIVE_ULONG))
0649             mdataString = readHDF5Data1D<unsigned long>(dataset, ctype, rows, lines, dataContainer[m]);
0650         else if (H5Tequal(mtype, H5T_STD_I64LE) || H5Tequal(mtype, H5T_STD_I64BE) || H5Tequal(mtype, H5T_NATIVE_LLONG))
0651             mdataString = readHDF5Data1D<long long>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0652         else if (H5Tequal(mtype, H5T_STD_U64LE) || H5Tequal(mtype, H5T_STD_U64BE) || H5Tequal(mtype, H5T_NATIVE_ULLONG))
0653             mdataString = readHDF5Data1D<unsigned long long>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0654         else if (H5Tequal(mtype, H5T_IEEE_F32LE) || H5Tequal(mtype, H5T_IEEE_F32BE))
0655             mdataString = readHDF5Data1D<float>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0656         else if (H5Tequal(mtype, H5T_IEEE_F64LE) || H5Tequal(mtype, H5T_IEEE_F64BE))
0657             mdataString = readHDF5Data1D<double>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]);
0658         else if (H5Tequal(mtype, H5T_NATIVE_LDOUBLE))
0659             mdataString = readHDF5Data1D<long double>(dataset, ctype, rows, lines, dataContainer[m]);
0660         else {
0661             if (dataContainer[m]) {
0662                 for (int row = startRow - 1; row < std::min(endRow, lines + startRow - 1); ++row)
0663                     static_cast<QVector<double>*>(dataContainer[m])->operator[](row - startRow + 1) = 0;
0664             } else {
0665                 for (int i = 0; i < std::min(rows, lines); ++i)
0666                     mdataString << QStringLiteral("_");
0667             }
0668             H5T_class_t mclass = H5Tget_member_class(tid, m);
0669             handleError((int)mclass, QStringLiteral("H5Tget_member_class"));
0670             DEBUG(Q_FUNC_INFO << ", unsupported type of class " << STDSTRING(translateHDF5Class(mclass)));
0671         }
0672 
0673         if (preview) {
0674             for (int i = 0; i < std::min(rows, lines); ++i) {
0675                 dataString[i] += mdataString[i];
0676                 if (m < members - 1)
0677                     dataString[i] += QLatin1String(",");
0678             }
0679         }
0680 
0681         H5Tclose(ctype);
0682     }
0683 
0684     if (preview) {
0685         for (int i = 0; i < std::min(rows, lines); ++i)
0686             dataString[i] += QLatin1String(")");
0687     }
0688 
0689     return dataString;
0690 }
0691 
0692 template<typename T>
0693 QVector<QStringList> HDF5FilterPrivate::readHDF5Data2D(hid_t dataset, hid_t dtype, int rows, int cols, int lines, std::vector<void*>& dataPointer) {
0694     DEBUG(Q_FUNC_INFO << ", rows = " << rows << ", cols = " << cols << ", lines = " << lines);
0695     QVector<QStringList> dataStrings;
0696 
0697     if (rows == 0 || cols == 0)
0698         return dataStrings;
0699 
0700     // read all data
0701     T** data = (T**)malloc(rows * sizeof(T*));
0702     data[0] = (T*)malloc(cols * rows * sizeof(T));
0703     for (int i = 1; i < rows; ++i)
0704         data[i] = data[0] + i * cols;
0705 
0706     m_status = H5Dread(dataset, dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data[0][0]);
0707     handleError(m_status, QStringLiteral("H5Dread"));
0708 
0709     H5T_class_t dclass = H5Tget_class(dtype);
0710     handleError((int)dclass, QStringLiteral("H5Dget_class"));
0711     if (dclass == H5T_INTEGER) {
0712         if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG) || H5Tequal(dtype, H5T_STD_U64LE)
0713             || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG)) {
0714             HDF5_READ_2D(qint64);
0715         } else
0716             HDF5_READ_2D(int);
0717     } else
0718         HDF5_READ_2D(double);
0719 
0720     free(data[0]);
0721     free(data);
0722 
0723     // QDEBUG(dataStrings);
0724     return dataStrings;
0725 }
0726 
0727 QVector<QStringList> HDF5FilterPrivate::readHDF5CompoundData2D(hid_t dataset, hid_t tid, int rows, int cols, int lines) {
0728     DEBUG(Q_FUNC_INFO << ", rows =" << rows << "cols = " << cols << "lines = " << lines);
0729 
0730     int members = H5Tget_nmembers(tid);
0731     handleError(members, QStringLiteral("H5Tget_nmembers"));
0732     DEBUG(" # members =" << members);
0733 
0734     QVector<QStringList> dataStrings;
0735     for (int i = 0; i < std::min(rows, lines); ++i) {
0736         QStringList lineStrings;
0737         for (int j = 0; j < cols; ++j)
0738             lineStrings << QStringLiteral("(");
0739         dataStrings << lineStrings;
0740     }
0741 
0742     // QStringList* data = new QStringList[members];
0743     for (int m = 0; m < members; ++m) {
0744         hid_t mtype = H5Tget_member_type(tid, m);
0745         handleError((int)mtype, QStringLiteral("H5Tget_member_type"));
0746         size_t msize = H5Tget_size(mtype);
0747         handleError((int)msize, QStringLiteral("H5Tget_size"));
0748         hid_t ctype = H5Tcreate(H5T_COMPOUND, msize);
0749         handleError((int)ctype, QStringLiteral("H5Tcreate"));
0750         m_status = H5Tinsert(ctype, H5Tget_member_name(tid, m), 0, mtype);
0751         handleError(m_status, QStringLiteral("H5Tinsert"));
0752 
0753         // dummy container for all data columns
0754         // initially contains one pointer set to NULL
0755         std::vector<void*> dummy(1, nullptr);
0756         QVector<QStringList> mdataStrings;
0757         if (H5Tequal(mtype, H5T_STD_I8LE) || H5Tequal(mtype, H5T_STD_I8BE))
0758             mdataStrings = readHDF5Data2D<qint8>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0759         else if (H5Tequal(mtype, H5T_NATIVE_CHAR)) {
0760             switch (sizeof(H5T_NATIVE_CHAR)) {
0761             case 1:
0762                 mdataStrings = readHDF5Data2D<qint8>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0763                 break;
0764             case 2:
0765                 mdataStrings = readHDF5Data2D<qint16>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0766                 break;
0767             case 4:
0768                 mdataStrings = readHDF5Data2D<qint32>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0769                 break;
0770             case 8:
0771                 mdataStrings = readHDF5Data2D<qint64>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0772                 break;
0773             }
0774         } else if (H5Tequal(mtype, H5T_STD_U8LE) || H5Tequal(mtype, H5T_STD_U8BE))
0775             mdataStrings = readHDF5Data2D<uint8_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0776         else if (H5Tequal(mtype, H5T_NATIVE_UCHAR)) {
0777             switch (sizeof(H5T_NATIVE_UCHAR)) {
0778             case 1:
0779                 mdataStrings = readHDF5Data2D<uint8_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0780                 break;
0781             case 2:
0782                 mdataStrings = readHDF5Data2D<uint16_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0783                 break;
0784             case 4:
0785                 mdataStrings = readHDF5Data2D<uint32_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0786                 break;
0787             case 8:
0788                 mdataStrings = readHDF5Data2D<uint64_t>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0789                 break;
0790             }
0791         } else if (H5Tequal(mtype, H5T_STD_I16LE) || H5Tequal(mtype, H5T_STD_I16BE) || H5Tequal(mtype, H5T_NATIVE_SHORT))
0792             mdataStrings = readHDF5Data2D<short>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0793         else if (H5Tequal(mtype, H5T_STD_U16LE) || H5Tequal(mtype, H5T_STD_U16BE) || H5Tequal(mtype, H5T_NATIVE_USHORT))
0794             mdataStrings = readHDF5Data2D<unsigned short>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0795         else if (H5Tequal(mtype, H5T_STD_I32LE) || H5Tequal(mtype, H5T_STD_I32BE) || H5Tequal(mtype, H5T_NATIVE_INT))
0796             mdataStrings = readHDF5Data2D<int>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0797         else if (H5Tequal(mtype, H5T_STD_U32LE) || H5Tequal(mtype, H5T_STD_U32BE) || H5Tequal(mtype, H5T_NATIVE_UINT))
0798             mdataStrings = readHDF5Data2D<unsigned int>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0799         else if (H5Tequal(mtype, H5T_NATIVE_LONG))
0800             mdataStrings = readHDF5Data2D<long>(dataset, ctype, rows, cols, lines, dummy);
0801         else if (H5Tequal(mtype, H5T_NATIVE_ULONG))
0802             mdataStrings = readHDF5Data2D<unsigned long>(dataset, ctype, rows, cols, lines, dummy);
0803         else if (H5Tequal(mtype, H5T_STD_I64LE) || H5Tequal(mtype, H5T_STD_I64BE) || H5Tequal(mtype, H5T_NATIVE_LLONG))
0804             mdataStrings = readHDF5Data2D<long long>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0805         else if (H5Tequal(mtype, H5T_STD_U64LE) || H5Tequal(mtype, H5T_STD_U64BE) || H5Tequal(mtype, H5T_NATIVE_ULLONG))
0806             mdataStrings = readHDF5Data2D<unsigned long long>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0807         else if (H5Tequal(mtype, H5T_IEEE_F32LE) || H5Tequal(mtype, H5T_IEEE_F32BE))
0808             mdataStrings = readHDF5Data2D<float>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0809         else if (H5Tequal(mtype, H5T_IEEE_F64LE) || H5Tequal(mtype, H5T_IEEE_F64BE))
0810             mdataStrings = readHDF5Data2D<double>(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy);
0811         else if (H5Tequal(mtype, H5T_NATIVE_LDOUBLE))
0812             mdataStrings = readHDF5Data2D<long double>(dataset, ctype, rows, cols, lines, dummy);
0813         else {
0814             for (int i = 0; i < std::min(rows, lines); ++i) {
0815                 QStringList lineString;
0816                 for (int j = 0; j < cols; ++j)
0817                     lineString << QStringLiteral("_");
0818                 mdataStrings << lineString;
0819             }
0820 #ifndef NDEBUG
0821             H5T_class_t mclass = H5Tget_member_class(tid, m);
0822             DEBUG("unsupported class " << STDSTRING(translateHDF5Class(mclass)));
0823 #endif
0824         }
0825 
0826         m_status = H5Tclose(ctype);
0827         handleError(m_status, QStringLiteral("H5Tclose"));
0828 
0829         for (int i = 0; i < std::min(rows, lines); i++) {
0830             for (int j = 0; j < cols; j++) {
0831                 dataStrings[i][j] += mdataStrings[i][j];
0832                 if (m < members - 1)
0833                     dataStrings[i][j] += QStringLiteral(",");
0834             }
0835         }
0836     }
0837 
0838     for (int i = 0; i < std::min(rows, lines); ++i) {
0839         for (int j = 0; j < cols; ++j)
0840             dataStrings[i][j] += QStringLiteral(")");
0841     }
0842 
0843     // QDEBUG("dataStrings =" << dataStrings);
0844     return dataStrings;
0845 }
0846 
0847 QStringList HDF5FilterPrivate::readHDF5Attr(hid_t aid) {
0848     QStringList attr;
0849 
0850     char name[MAXNAMELENGTH];
0851     m_status = H5Aget_name(aid, MAXNAMELENGTH, name);
0852     handleError(m_status, QStringLiteral("H5Aget_name"));
0853     attr << QLatin1String(name);
0854     // DEBUG(Q_FUNC_INFO << ", name =" << name);
0855 
0856     hid_t aspace = H5Aget_space(aid); // the dimensions of the attribute data
0857     handleError((int)aspace, QStringLiteral("H5Aget_space"));
0858     hid_t atype = H5Aget_type(aid);
0859     handleError((int)atype, QStringLiteral("H5Aget_type"));
0860     hid_t aclass = H5Tget_class(atype);
0861     handleError((int)aclass, QStringLiteral("H5Aget_class"));
0862 
0863     if (aclass == H5T_STRING) {
0864         hid_t amem = H5Tget_native_type(atype, H5T_DIR_DEFAULT);
0865         handleError((int)amem, QStringLiteral("H5Aget_native_type"));
0866         htri_t isVariable = H5Tis_variable_str(amem);
0867         handleError((int)isVariable, QStringLiteral("H5Tis_variable_str"));
0868         // DEBUG("variable string: " << isVariable)
0869         char* buf = nullptr; // buffer to read attr value
0870         if (!isVariable) { // fixed length
0871             hsize_t sz = H5Tget_size(atype);
0872             handleError((int)sz, QStringLiteral("H5Aget_storage_size"));
0873             // DEBUG("variable string = " << isVariable << ", storage size = " << sz)
0874             buf = new char[sz + 1];
0875             m_status = H5Aread(aid, amem, buf);
0876             buf[sz] = '\0';
0877         } else
0878             m_status = H5Aread(aid, amem, &buf);
0879         handleError(m_status, QStringLiteral("H5Aread"));
0880         attr << QLatin1String("=") << QLatin1String(buf);
0881         // DEBUG(Q_FUNC_INFO << ", value = " << buf)
0882         m_status = H5Tclose(amem);
0883         handleError(m_status, QStringLiteral("H5Tclose"));
0884     } else if (aclass == H5T_INTEGER) {
0885         if (H5Tequal(atype, H5T_STD_I8LE)) {
0886             qint8 value;
0887             m_status = H5Aread(aid, H5T_STD_I8LE, &value);
0888             handleError(m_status, QStringLiteral("H5Aread"));
0889             attr << QLatin1String("=") << QString::number(value);
0890         } else if (H5Tequal(atype, H5T_STD_I8BE)) {
0891             qint8 value;
0892             m_status = H5Aread(aid, H5T_STD_I8BE, &value);
0893             handleError(m_status, QStringLiteral("H5Aread"));
0894             attr << QLatin1String("=") << QString::number(value);
0895         } else if (H5Tequal(atype, H5T_NATIVE_CHAR)) {
0896             switch (sizeof(H5T_NATIVE_CHAR)) {
0897             case 1: {
0898                 qint8 value;
0899                 m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value);
0900                 handleError(m_status, QStringLiteral("H5Aread"));
0901                 attr << QLatin1String("=") << QString::number(value);
0902                 break;
0903             }
0904             case 2: {
0905                 qint16 value;
0906                 m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value);
0907                 handleError(m_status, QStringLiteral("H5Aread"));
0908                 attr << QLatin1String("=") << QString::number(value);
0909                 break;
0910             }
0911             case 4: {
0912                 qint32 value;
0913                 m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value);
0914                 handleError(m_status, QStringLiteral("H5Aread"));
0915                 attr << QLatin1String("=") << QString::number(value);
0916                 break;
0917             }
0918             case 8: {
0919                 qint64 value;
0920                 m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value);
0921                 handleError(m_status, QStringLiteral("H5Aread"));
0922                 attr << QLatin1String("=") << QString::number(value);
0923                 break;
0924             }
0925             default:
0926                 DEBUG("unknown size " << sizeof(H5T_NATIVE_CHAR) << " of H5T_NATIVE_CHAR");
0927                 return QStringList(QString());
0928             }
0929         } else if (H5Tequal(atype, H5T_STD_U8LE)) {
0930             uint8_t value;
0931             m_status = H5Aread(aid, H5T_STD_U8LE, &value);
0932             handleError(m_status, QStringLiteral("H5Aread"));
0933             attr << QLatin1String("=") << QString::number(value);
0934         } else if (H5Tequal(atype, H5T_STD_U8BE)) {
0935             uint8_t value;
0936             m_status = H5Aread(aid, H5T_STD_U8BE, &value);
0937             handleError(m_status, QStringLiteral("H5Aread"));
0938             attr << QLatin1String("=") << QString::number(value);
0939         } else if (H5Tequal(atype, H5T_NATIVE_UCHAR)) {
0940             switch (sizeof(H5T_NATIVE_UCHAR)) {
0941             case 1: {
0942                 uint8_t value;
0943                 m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value);
0944                 handleError(m_status, QStringLiteral("H5Aread"));
0945                 attr << QLatin1String("=") << QString::number(value);
0946                 break;
0947             }
0948             case 2: {
0949                 uint16_t value;
0950                 m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value);
0951                 handleError(m_status, QStringLiteral("H5Aread"));
0952                 attr << QLatin1String("=") << QString::number(value);
0953                 break;
0954             }
0955             case 4: {
0956                 uint32_t value;
0957                 m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value);
0958                 handleError(m_status, QStringLiteral("H5Aread"));
0959                 attr << QLatin1String("=") << QString::number(value);
0960                 break;
0961             }
0962             case 8: {
0963                 uint64_t value;
0964                 m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value);
0965                 handleError(m_status, QStringLiteral("H5Aread"));
0966                 attr << QLatin1String("=") << QString::number(value);
0967                 break;
0968             }
0969             default:
0970                 DEBUG("unknown size " << sizeof(H5T_NATIVE_UCHAR) << " of H5T_NATIVE_UCHAR");
0971                 return QStringList(QString());
0972             }
0973         } else if (H5Tequal(atype, H5T_STD_I16LE) || H5Tequal(atype, H5T_STD_I16BE) || H5Tequal(atype, H5T_NATIVE_SHORT)) {
0974             short value;
0975             m_status = H5Aread(aid, H5T_NATIVE_SHORT, &value);
0976             handleError(m_status, QStringLiteral("H5Aread"));
0977             attr << QLatin1String("=") << QString::number(value);
0978         } else if (H5Tequal(atype, H5T_STD_U16LE) || H5Tequal(atype, H5T_STD_U16BE) || H5Tequal(atype, H5T_NATIVE_USHORT)) {
0979             unsigned short value;
0980             m_status = H5Aread(aid, H5T_NATIVE_USHORT, &value);
0981             handleError(m_status, QStringLiteral("H5Aread"));
0982             attr << QLatin1String("=") << QString::number(value);
0983         } else if (H5Tequal(atype, H5T_STD_I32LE) || H5Tequal(atype, H5T_STD_I32BE) || H5Tequal(atype, H5T_NATIVE_INT)) {
0984             int value;
0985             m_status = H5Aread(aid, H5T_NATIVE_INT, &value);
0986             handleError(m_status, QStringLiteral("H5Aread"));
0987             attr << QLatin1String("=") << QString::number(value);
0988         } else if (H5Tequal(atype, H5T_STD_U32LE) || H5Tequal(atype, H5T_STD_U32BE) || H5Tequal(atype, H5T_NATIVE_UINT)) {
0989             unsigned int value;
0990             m_status = H5Aread(aid, H5T_NATIVE_UINT, &value);
0991             handleError(m_status, QStringLiteral("H5Aread"));
0992             attr << QLatin1String("=") << QString::number(value);
0993         } else if (H5Tequal(atype, H5T_NATIVE_LONG)) {
0994             long value;
0995             m_status = H5Aread(aid, H5T_NATIVE_LONG, &value);
0996             handleError(m_status, QStringLiteral("H5Aread"));
0997             attr << QLatin1String("=") << QString::number(value);
0998         } else if (H5Tequal(atype, H5T_NATIVE_ULONG)) {
0999             unsigned long value;
1000             m_status = H5Aread(aid, H5T_NATIVE_ULONG, &value);
1001             handleError(m_status, QStringLiteral("H5Aread"));
1002             attr << QLatin1String("=") << QString::number(value);
1003         } else if (H5Tequal(atype, H5T_STD_I64LE) || H5Tequal(atype, H5T_STD_I64BE) || H5Tequal(atype, H5T_NATIVE_LLONG)) {
1004             long long value;
1005             m_status = H5Aread(aid, H5T_NATIVE_LLONG, &value);
1006             handleError(m_status, QStringLiteral("H5Aread"));
1007             attr << QLatin1String("=") << QString::number(value);
1008         } else if (H5Tequal(atype, H5T_STD_U64LE) || H5Tequal(atype, H5T_STD_U64BE) || H5Tequal(atype, H5T_NATIVE_ULLONG)) {
1009             unsigned long long value;
1010             m_status = H5Aread(aid, H5T_NATIVE_ULLONG, &value);
1011             handleError(m_status, QStringLiteral("H5Aread"));
1012             attr << QLatin1String("=") << QString::number(value);
1013         } else
1014             attr << QStringLiteral(" (unknown integer)");
1015     } else if (aclass == H5T_FLOAT) {
1016         if (H5Tequal(atype, H5T_IEEE_F32LE) || H5Tequal(atype, H5T_IEEE_F32BE)) {
1017             float value;
1018             m_status = H5Aread(aid, H5T_NATIVE_FLOAT, &value);
1019             handleError(m_status, QStringLiteral("H5Aread"));
1020             attr << QLatin1String("=") << QString::number(value);
1021         } else if (H5Tequal(atype, H5T_IEEE_F64LE) || H5Tequal(atype, H5T_IEEE_F64BE)) {
1022             double value;
1023             m_status = H5Aread(aid, H5T_NATIVE_DOUBLE, &value);
1024             handleError(m_status, QStringLiteral("H5Aread"));
1025             attr << QLatin1String("=") << QString::number(value);
1026         } else if (H5Tequal(atype, H5T_NATIVE_LDOUBLE)) {
1027             long double value;
1028             m_status = H5Aread(aid, H5T_NATIVE_LDOUBLE, &value);
1029             handleError(m_status, QStringLiteral("H5Aread"));
1030             attr << QLatin1String("=") << QString::number((double)value);
1031         } else
1032             attr << QStringLiteral(" (unknown float)");
1033     }
1034 
1035     m_status = H5Tclose(atype);
1036     handleError(m_status, QStringLiteral("H5Tclose"));
1037     m_status = H5Sclose(aspace);
1038     handleError(m_status, QStringLiteral("H5Sclose"));
1039 
1040     return attr;
1041 }
1042 
1043 QStringList HDF5FilterPrivate::scanHDF5Attrs(hid_t oid) {
1044     QStringList attrList;
1045 
1046     int numAttr = H5Aget_num_attrs(oid);
1047     handleError(numAttr, QStringLiteral("H5Aget_num_attrs"));
1048     // DEBUG(Q_FUNC_INFO << ", number of attr = " << numAttr);
1049 
1050     for (int i = 0; i < numAttr; ++i) {
1051         hid_t aid = H5Aopen_idx(oid, i);
1052         handleError((int)aid, QStringLiteral("H5Aopen_idx"));
1053         attrList << readHDF5Attr(aid);
1054         if (i < numAttr - 1)
1055             attrList << QLatin1String(", ");
1056         m_status = H5Aclose(aid);
1057         handleError(m_status, QStringLiteral("H5Aclose"));
1058     }
1059 
1060     return attrList;
1061 }
1062 
1063 QStringList HDF5FilterPrivate::readHDF5DataType(hid_t tid) {
1064     H5T_class_t typeClass = H5Tget_class(tid);
1065     handleError((int)typeClass, QStringLiteral("H5Tget_class"));
1066 
1067     QStringList typeProps;
1068     QString typeString = translateHDF5Class(typeClass);
1069     if (typeClass == H5T_INTEGER || typeClass == H5T_FLOAT)
1070         typeString = translateHDF5Type(tid);
1071     typeProps << typeString;
1072 
1073     size_t size = H5Tget_size(tid);
1074     typeProps << QLatin1String(" (") << QString::number(size) << QLatin1String(") ");
1075 
1076     H5T_order_t order = H5Tget_order(tid);
1077     handleError((int)order, QStringLiteral("H5Tget_order"));
1078     typeProps << translateHDF5Order(order);
1079 
1080     // type specific props
1081     switch (typeClass) {
1082     case H5T_STRING: {
1083         H5T_cset_t cset = H5Tget_cset(tid);
1084         handleError((int)cset, QStringLiteral("H5Tget_cset"));
1085         switch (cset) {
1086         case H5T_CSET_ASCII:
1087             typeProps << QLatin1String(", ASCII");
1088             break;
1089         case H5T_CSET_ERROR:
1090             typeProps << QLatin1String(", ERROR");
1091             break;
1092         case H5T_CSET_UTF8:
1093             typeProps << QLatin1String(", UTF8");
1094             break;
1095         case H5T_CSET_RESERVED_2:
1096         case H5T_CSET_RESERVED_3:
1097         case H5T_CSET_RESERVED_4:
1098         case H5T_CSET_RESERVED_5:
1099         case H5T_CSET_RESERVED_6:
1100         case H5T_CSET_RESERVED_7:
1101         case H5T_CSET_RESERVED_8:
1102         case H5T_CSET_RESERVED_9:
1103         case H5T_CSET_RESERVED_10:
1104         case H5T_CSET_RESERVED_11:
1105         case H5T_CSET_RESERVED_12:
1106         case H5T_CSET_RESERVED_13:
1107         case H5T_CSET_RESERVED_14:
1108         case H5T_CSET_RESERVED_15:
1109             typeProps << QLatin1String(", RESERVED");
1110             break;
1111         }
1112         H5T_str_t strpad = H5Tget_strpad(tid);
1113         handleError((int)strpad, QStringLiteral("H5Tget_strpad"));
1114         switch (strpad) {
1115         case H5T_STR_NULLTERM:
1116             typeProps << QLatin1String(" NULLTERM");
1117             break;
1118         case H5T_STR_NULLPAD:
1119             typeProps << QLatin1String(" NULLPAD");
1120             break;
1121         case H5T_STR_SPACEPAD:
1122             typeProps << QLatin1String(" SPACEPAD");
1123             break;
1124         case H5T_STR_ERROR:
1125             typeProps << QLatin1String(" ERROR");
1126             break;
1127         case H5T_STR_RESERVED_3:
1128         case H5T_STR_RESERVED_4:
1129         case H5T_STR_RESERVED_5:
1130         case H5T_STR_RESERVED_6:
1131         case H5T_STR_RESERVED_7:
1132         case H5T_STR_RESERVED_8:
1133         case H5T_STR_RESERVED_9:
1134         case H5T_STR_RESERVED_10:
1135         case H5T_STR_RESERVED_11:
1136         case H5T_STR_RESERVED_12:
1137         case H5T_STR_RESERVED_13:
1138         case H5T_STR_RESERVED_14:
1139         case H5T_STR_RESERVED_15:
1140             typeProps << QLatin1String(" RESERVED");
1141             break;
1142         }
1143         break;
1144     }
1145     case H5T_COMPOUND: {
1146         // not shown in tree widget
1147         // QDEBUG(readHDF5Compound(tid).join(QString()));
1148         break;
1149     }
1150     case H5T_ENUM: {
1151         // TODO
1152         break;
1153     }
1154     case H5T_INTEGER:
1155         // TODO
1156         break;
1157     case H5T_FLOAT:
1158         // TODO
1159         break;
1160     case H5T_TIME:
1161         // TODO
1162         break;
1163     case H5T_BITFIELD:
1164         // TODO
1165         break;
1166     case H5T_OPAQUE:
1167         // TODO
1168         break;
1169     case H5T_REFERENCE:
1170         // TODO
1171         break;
1172     case H5T_VLEN:
1173         // TODO
1174         break;
1175     case H5T_ARRAY:
1176         // TODO
1177         break;
1178     case H5T_NCLASSES:
1179         // TODO
1180         break;
1181     case H5T_NO_CLASS:
1182         break;
1183     }
1184 
1185     return typeProps;
1186 }
1187 
1188 QStringList HDF5FilterPrivate::readHDF5PropertyList(hid_t pid) {
1189     QStringList props;
1190 
1191     hsize_t chunk_dims_out[2];
1192     if (H5D_CHUNKED == H5Pget_layout(pid)) {
1193         int rank_chunk = H5Pget_chunk(pid, 2, chunk_dims_out);
1194         handleError(rank_chunk, QStringLiteral("H5Pget_chunk"));
1195         props << QLatin1String("chunk rank=") << QString::number(rank_chunk) << QLatin1String(", dimension=") << QString::number(chunk_dims_out[0])
1196               << QString::number(chunk_dims_out[1]);
1197     }
1198 
1199     int nfilters = H5Pget_nfilters(pid);
1200     handleError(nfilters, QStringLiteral("H5Pget_nfilters"));
1201     props << QLatin1String(" ") << QString::number(nfilters) << QLatin1String(" filter");
1202     for (int i = 0; i < nfilters; ++i) {
1203         size_t cd_nelmts = 32;
1204         unsigned int filt_flags, filt_conf;
1205         unsigned int cd_values[32];
1206         char f_name[MAXNAMELENGTH];
1207         H5Z_filter_t filtn = H5Pget_filter(pid, (unsigned)i, &filt_flags, &cd_nelmts, cd_values, (size_t)MAXNAMELENGTH, f_name, &filt_conf);
1208         handleError((int)filtn, QStringLiteral("H5Pget_filter"));
1209 
1210         switch (filtn) {
1211         case H5Z_FILTER_DEFLATE: /* AKA GZIP compression */
1212             props << QLatin1String(": DEFLATE level =") << QString::number(cd_values[0]);
1213             break;
1214         case H5Z_FILTER_SHUFFLE:
1215             props << QLatin1String(": SHUFFLE"); /* no parms */
1216             break;
1217         case H5Z_FILTER_FLETCHER32:
1218             props << QLatin1String(": FLETCHER32"); /* Error Detection Code */
1219             break;
1220         case H5Z_FILTER_SZIP: {
1221             // unsigned int szip_options_mask = cd_values[0];
1222             unsigned int szip_pixels_per_block = cd_values[1];
1223 
1224             props << QLatin1String(": SZIP COMPRESSION - PIXELS_PER_BLOCK ") << QString::number(szip_pixels_per_block);
1225             break;
1226         }
1227         default:
1228             props << QLatin1String(": Unknown filter");
1229             break;
1230         }
1231     }
1232 
1233     props << QLatin1String(", ALLOC_TIME:");
1234     H5D_alloc_time_t at;
1235     m_status = H5Pget_alloc_time(pid, &at);
1236     handleError(m_status, QStringLiteral("H5Pget_alloc_time"));
1237 
1238     switch (at) {
1239     case H5D_ALLOC_TIME_EARLY:
1240         props << QLatin1String(" EARLY");
1241         break;
1242     case H5D_ALLOC_TIME_INCR:
1243         props << QLatin1String(" INCR");
1244         break;
1245     case H5D_ALLOC_TIME_LATE:
1246         props << QLatin1String(" LATE");
1247         break;
1248     case H5D_ALLOC_TIME_DEFAULT:
1249         props << QLatin1String(" DEFAULT");
1250         break;
1251     case H5D_ALLOC_TIME_ERROR:
1252         props << QLatin1String(" ERROR");
1253         break;
1254     }
1255 
1256     props << QLatin1String(", FILL_TIME:");
1257     H5D_fill_time_t ft;
1258     m_status = H5Pget_fill_time(pid, &ft);
1259     handleError(m_status, QStringLiteral("H5Pget_fill_time"));
1260     switch (ft) {
1261     case H5D_FILL_TIME_ALLOC:
1262         props << QLatin1String(" ALLOW");
1263         break;
1264     case H5D_FILL_TIME_NEVER:
1265         props << QLatin1String(" NEVER");
1266         break;
1267     case H5D_FILL_TIME_IFSET:
1268         props << QLatin1String(" IFSET");
1269         break;
1270     case H5D_FILL_TIME_ERROR:
1271         props << QLatin1String(" ERROR");
1272         break;
1273     }
1274 
1275     H5D_fill_value_t fvstatus;
1276     m_status = H5Pfill_value_defined(pid, &fvstatus);
1277     handleError(m_status, QStringLiteral("H5Pfill_value_defined"));
1278     if (fvstatus == H5D_FILL_VALUE_UNDEFINED)
1279         props << QLatin1String(" No fill value defined");
1280     else {
1281         /* TODO: Read  the fill value with H5Pget_fill_value.
1282          * Fill value is the same data type as the dataset.
1283          * (details not shown)
1284          **/
1285     }
1286 
1287     return props;
1288 }
1289 
1290 void HDF5FilterPrivate::scanHDF5DataType(hid_t tid, char* dataSetName, QTreeWidgetItem* parentItem) {
1291     QStringList typeProps = readHDF5DataType(tid);
1292 
1293     QString attr = scanHDF5Attrs(tid).join(QLatin1Char(' '));
1294 
1295     char link[MAXNAMELENGTH];
1296     m_status = H5Iget_name(tid, link, MAXNAMELENGTH);
1297     handleError(m_status, QStringLiteral("H5Iget_name"));
1298 
1299     auto* dataTypeItem =
1300         new QTreeWidgetItem(QStringList() << QLatin1String(dataSetName) << QLatin1String(link) << i18n("data type") << typeProps.join(QString()) << attr);
1301     dataTypeItem->setIcon(0, QIcon::fromTheme(QStringLiteral("accessories-calculator")));
1302     dataTypeItem->setFlags(Qt::ItemIsEnabled);
1303     parentItem->addChild(dataTypeItem);
1304 }
1305 
1306 void HDF5FilterPrivate::scanHDF5DataSet(hid_t did, char* dataSetName, QTreeWidgetItem* parentItem) {
1307     QString attr = scanHDF5Attrs(did).join(QString());
1308 
1309     char link[MAXNAMELENGTH];
1310     m_status = H5Iget_name(did, link, MAXNAMELENGTH);
1311     handleError(m_status, QStringLiteral("H5Iget_name"));
1312 
1313     QStringList dataSetProps;
1314     hsize_t size = H5Dget_storage_size(did);
1315     handleError((int)size, QStringLiteral("H5Dget_storage_size"));
1316     hid_t datatype = H5Dget_type(did);
1317     handleError((int)datatype, QStringLiteral("H5Dget_type"));
1318     size_t typeSize = H5Tget_size(datatype);
1319     handleError((int)typeSize, QStringLiteral("H5Dget_size"));
1320 
1321     dataSetProps << readHDF5DataType(datatype);
1322 
1323     hid_t dataspace = H5Dget_space(did);
1324     int rank = H5Sget_simple_extent_ndims(dataspace);
1325     handleError(rank, QStringLiteral("H5Sget_simple_extent_ndims"));
1326     unsigned int rows = 1, cols = 1, regs = 1;
1327     if (rank == 1) {
1328         hsize_t dims_out[1];
1329         m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr);
1330         handleError(m_status, QStringLiteral("H5Sget_simple_extent_dims"));
1331         rows = dims_out[0];
1332         dataSetProps << QLatin1String(", ") << QString::number(rows) << QLatin1String(" (") << QString::number(size / typeSize) << QLatin1String(")");
1333     } else if (rank == 2) {
1334         hsize_t dims_out[2];
1335         m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr);
1336         handleError(m_status, QStringLiteral("H5Sget_simple_extent_dims"));
1337         rows = dims_out[0];
1338         cols = dims_out[1];
1339         dataSetProps << QLatin1String(", ") << QString::number(rows) << QLatin1String("x") << QString::number(cols) << QLatin1String(" (")
1340                      << QString::number(size / typeSize) << QLatin1String(")");
1341     } else if (rank == 3) {
1342         hsize_t dims_out[3];
1343         m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr);
1344         handleError(m_status, QStringLiteral("H5Sget_simple_extent_dims"));
1345         rows = dims_out[0];
1346         cols = dims_out[1];
1347         regs = dims_out[2];
1348         dataSetProps << QLatin1String(", ") << QString::number(rows) << QLatin1String("x") << QString::number(cols) << QLatin1String("x")
1349                      << QString::number(regs) << QLatin1String(" (") << QString::number(size / typeSize) << QLatin1String(")");
1350     } else
1351         dataSetProps << QLatin1String(", ") << i18n("rank %1 not supported yet", rank);
1352 
1353     hid_t pid = H5Dget_create_plist(did);
1354     handleError((int)pid, QStringLiteral("H5Dget_create_plist"));
1355     dataSetProps << QStringLiteral(", ") << readHDF5PropertyList(pid).join(QString());
1356 
1357     auto* dataSetItem =
1358         new QTreeWidgetItem(QStringList() << QLatin1String(dataSetName) << QLatin1String(link) << i18n("data set") << dataSetProps.join(QString()) << attr);
1359     dataSetItem->setIcon(0, QIcon::fromTheme(QStringLiteral("x-office-spreadsheet")));
1360     for (int i = 0; i < dataSetItem->columnCount(); ++i) {
1361         if (rows > 0 && cols > 0 && regs > 0) {
1362             dataSetItem->setBackground(i, QColor(192, 255, 192));
1363             dataSetItem->setForeground(i, Qt::black);
1364             dataSetItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
1365         } else
1366             dataSetItem->setFlags(Qt::NoItemFlags);
1367     }
1368     parentItem->addChild(dataSetItem);
1369 }
1370 
1371 void HDF5FilterPrivate::scanHDF5Link(hid_t gid, char* linkName, QTreeWidgetItem* parentItem) {
1372     char target[MAXNAMELENGTH];
1373     m_status = H5Gget_linkval(gid, linkName, MAXNAMELENGTH, target);
1374     handleError(m_status, QStringLiteral("H5Gget_linkval"));
1375 
1376     auto* linkItem = new QTreeWidgetItem(QStringList() << QLatin1String(linkName) << i18n("symbolic link") << i18n("link to %1", QFile::decodeName(target)));
1377     linkItem->setIcon(0, QIcon::fromTheme(QStringLiteral("emblem-symbolic-link")));
1378     linkItem->setFlags(Qt::ItemIsEnabled);
1379     parentItem->addChild(linkItem);
1380 }
1381 
1382 void HDF5FilterPrivate::scanHDF5Group(hid_t gid, char* groupName, QTreeWidgetItem* parentItem) {
1383     // check for hard link
1384     H5G_stat_t statbuf;
1385     m_status = H5Gget_objinfo(gid, ".", true, &statbuf);
1386     handleError(m_status, QStringLiteral("H5Gget_objinfo"));
1387     if (statbuf.nlink > 1) {
1388         if (m_multiLinkList.contains(statbuf.objno[0])) {
1389             auto* objectItem = new QTreeWidgetItem(QStringList() << QLatin1String(groupName) << i18n("hard link"));
1390             objectItem->setIcon(0, QIcon::fromTheme(QStringLiteral("link")));
1391             objectItem->setFlags(Qt::ItemIsEnabled);
1392             parentItem->addChild(objectItem);
1393             return;
1394         } else {
1395             m_multiLinkList.append(statbuf.objno[0]);
1396             DEBUG(" group multiple links: " << statbuf.objno[0] << ' ' << statbuf.objno[1]);
1397         }
1398     }
1399 
1400     char link[MAXNAMELENGTH];
1401     m_status = H5Iget_name(gid, link, MAXNAMELENGTH);
1402     handleError(m_status, QStringLiteral("H5Iget_name"));
1403 
1404     QString attr = scanHDF5Attrs(gid).join(QLatin1Char(' '));
1405 
1406     auto* groupItem = new QTreeWidgetItem(QStringList() << QLatin1String(groupName) << QLatin1String(link) << QStringLiteral("group ") << attr);
1407     groupItem->setIcon(0, QIcon::fromTheme(QStringLiteral("folder")));
1408     groupItem->setFlags(Qt::ItemIsEnabled);
1409     parentItem->addChild(groupItem);
1410 
1411     hsize_t numObj;
1412     m_status = H5Gget_num_objs(gid, &numObj);
1413     handleError(m_status, QStringLiteral("H5Gget_num_objs"));
1414     // DEBUG(Q_FUNC_INFO << ", # of objects = " << numObj)
1415 
1416     for (unsigned int i = 0; i < numObj; ++i) {
1417         char memberName[MAXNAMELENGTH];
1418         m_status = H5Gget_objname_by_idx(gid, (hsize_t)i, memberName, (size_t)MAXNAMELENGTH);
1419         handleError(m_status, QStringLiteral("H5Gget_objname_by_idx"));
1420 
1421         int otype = H5Gget_objtype_by_idx(gid, (size_t)i);
1422         handleError(otype, QStringLiteral("H5Gget_objtype_by_idx"));
1423         switch (otype) {
1424         case H5G_LINK: {
1425             scanHDF5Link(gid, memberName, groupItem);
1426             break;
1427         }
1428         case H5G_GROUP: {
1429             hid_t grpid = H5Gopen(gid, memberName, H5P_DEFAULT);
1430             handleError((int)grpid, QStringLiteral("H5Gopen"));
1431             scanHDF5Group(grpid, memberName, groupItem);
1432             m_status = H5Gclose(grpid);
1433             handleError(m_status, QStringLiteral("H5Gclose"));
1434             break;
1435         }
1436         case H5G_DATASET: {
1437             hid_t dsid = H5Dopen(gid, memberName, H5P_DEFAULT);
1438             handleError((int)dsid, QStringLiteral("H5Dopen"));
1439             scanHDF5DataSet(dsid, memberName, groupItem);
1440             m_status = H5Dclose(dsid);
1441             handleError(m_status, QStringLiteral("H5Dclose"));
1442             break;
1443         }
1444         case H5G_TYPE: {
1445             hid_t tid = H5Topen(gid, memberName, H5P_DEFAULT);
1446             handleError((int)tid, QStringLiteral("H5Topen"));
1447             scanHDF5DataType(tid, memberName, groupItem);
1448             m_status = H5Tclose(tid);
1449             handleError(m_status, QStringLiteral("H5Tclose"));
1450             break;
1451         }
1452         default:
1453             auto* objectItem = new QTreeWidgetItem(QStringList() << QLatin1String(memberName) << i18n("unknown"));
1454             objectItem->setFlags(Qt::ItemIsEnabled);
1455             groupItem->addChild(objectItem);
1456             break;
1457         }
1458     }
1459 }
1460 #endif
1461 
1462 /*!
1463     parses the content of the file \c fileName and fill the tree using rootItem.
1464     returns -1 on error
1465 */
1466 int HDF5FilterPrivate::parse(const QString& fileName, QTreeWidgetItem* rootItem) {
1467 #ifdef HAVE_HDF5
1468     DEBUG(Q_FUNC_INFO << ", fileName = " << qPrintable(fileName));
1469 
1470     // check file type first
1471     htri_t isHdf5 = H5Fis_hdf5(qPrintable(fileName));
1472     if (isHdf5 == 0) { // not an HDF5 file
1473         DEBUG(qPrintable(fileName) << " is not a HDF5 file! Giving up.");
1474         return -1;
1475     }
1476     if (isHdf5 < 0) { // failing on file (like not found)
1477         DEBUG("H5Fis_hdf5() failed on " << qPrintable(fileName) << "! Giving up.");
1478         return -1;
1479     }
1480 
1481     // open file
1482     hid_t file = H5Fopen(qPrintable(fileName), H5F_ACC_RDONLY, H5P_DEFAULT);
1483     handleError((int)file, QStringLiteral("H5Fopen"), fileName);
1484     if (file < 0) {
1485         DEBUG("Opening file " << qPrintable(fileName) << " failed! Giving up.");
1486         return -1;
1487     }
1488     char rootName[] = "/";
1489     hid_t group = H5Gopen(file, rootName, H5P_DEFAULT);
1490     handleError((int)group, QStringLiteral("H5Gopen"), QLatin1String(rootName));
1491     // multiLinkList.clear(); crashes
1492     scanHDF5Group(group, rootName, rootItem);
1493     m_status = H5Gclose(group);
1494     handleError(m_status, QStringLiteral("H5Gclose"), QString());
1495     m_status = H5Fclose(file);
1496     handleError(m_status, QStringLiteral("H5Fclose"), QString());
1497 #else
1498     DEBUG(Q_FUNC_INFO << ", HDF5 not available");
1499     Q_UNUSED(fileName)
1500     Q_UNUSED(rootItem)
1501 #endif
1502     return 0;
1503 }
1504 
1505 /*!
1506     reads the content of the date set in the file \c fileName to a string (for preview) or to the data source.
1507 */
1508 QVector<QStringList>
1509 HDF5FilterPrivate::readCurrentDataSet(const QString& fileName, AbstractDataSource* dataSource, bool& ok, AbstractFileFilter::ImportMode mode, int lines) {
1510     QVector<QStringList> dataStrings;
1511 
1512     if (currentDataSetName.isEmpty()) {
1513         // return QString("No data set selected").replace(QLatin1Char(' '),QChar::Nbsp);
1514         ok = false;
1515         return dataStrings << (QStringList() << i18n("No data set selected"));
1516     }
1517     DEBUG(Q_FUNC_INFO << ", current data set = " << STDSTRING(currentDataSetName));
1518 
1519 #ifdef HAVE_HDF5
1520     hid_t file = H5Fopen(qPrintable(fileName), H5F_ACC_RDONLY, H5P_DEFAULT);
1521     handleError((int)file, QStringLiteral("H5Fopen"), fileName);
1522     hid_t dataset = H5Dopen2(file, qPrintable(currentDataSetName), H5P_DEFAULT);
1523     handleError((int)file, QStringLiteral("H5Dopen2"), currentDataSetName);
1524 
1525     // Get datatype and dataspace
1526     hid_t dtype = H5Dget_type(dataset);
1527     handleError((int)dtype, QStringLiteral("H5Dget_type"));
1528     DEBUG(Q_FUNC_INFO << ", type = " << STDSTRING(translateHDF5Type(dtype)))
1529     H5T_class_t dclass = H5Tget_class(dtype);
1530     handleError((int)dclass, QStringLiteral("H5Dget_class"));
1531     DEBUG(Q_FUNC_INFO << ", class = " << STDSTRING(translateHDF5Class(dclass)))
1532     size_t typeSize = H5Tget_size(dtype);
1533     handleError((int)(typeSize - 1), QStringLiteral("H5Dget_size"));
1534 
1535     hid_t dataspace = H5Dget_space(dataset);
1536     handleError((int)dataspace, QStringLiteral("H5Dget_space"));
1537     int rank = H5Sget_simple_extent_ndims(dataspace);
1538     handleError(rank, QStringLiteral("H5Dget_simple_extent_ndims"));
1539     DEBUG(Q_FUNC_INFO << ", rank = " << rank);
1540 
1541     int columnOffset = 0; // offset to import data
1542     int actualRows = 0, actualCols = 0; // rows and cols to read
1543 
1544     // dataContainer is used to store the data read from the dataSource
1545     // it contains the pointers of all columns
1546     // initially there is one pointer set to nullptr
1547     // check for dataContainer[0] to decide if dataSource can be used
1548     std::vector<void*> dataContainer(1, nullptr);
1549 
1550     // rank= 0: single value, 1: vector, 2: matrix, 3: 3D data, ...
1551     switch (rank) {
1552     case 0: { // single value
1553         actualCols = 1;
1554 
1555         switch (dclass) {
1556         case H5T_STRING: {
1557             char* data = (char*)malloc(typeSize * sizeof(char));
1558             hid_t memtype = H5Tcopy(H5T_C_S1);
1559             handleError((int)memtype, QStringLiteral("H5Tcopy"));
1560             m_status = H5Tset_size(memtype, typeSize);
1561             handleError(m_status, QStringLiteral("H5Tset_size"));
1562 
1563             m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
1564             handleError(m_status, QStringLiteral("H5Tread"));
1565             dataStrings << (QStringList() << QLatin1String(data));
1566             free(data);
1567             break;
1568         }
1569         case H5T_INTEGER:
1570         case H5T_FLOAT:
1571         case H5T_TIME:
1572         case H5T_BITFIELD:
1573         case H5T_OPAQUE:
1574         case H5T_COMPOUND:
1575         case H5T_REFERENCE:
1576         case H5T_ENUM:
1577         case H5T_VLEN:
1578         case H5T_ARRAY:
1579         case H5T_NO_CLASS:
1580         case H5T_NCLASSES: {
1581             ok = false;
1582             dataStrings << (QStringList() << i18n("rank 0 not implemented yet for type %1", translateHDF5Class(dclass)));
1583             QDEBUG(dataStrings);
1584         }
1585         default:
1586             break;
1587         }
1588         break;
1589     }
1590     case 1: { // 1D data
1591         hsize_t size, maxSize;
1592         m_status = H5Sget_simple_extent_dims(dataspace, &size, &maxSize);
1593         handleError(m_status, QStringLiteral("H5Sget_simple_extent_dims"));
1594         int rows = size;
1595         if (endRow == -1 && dclass != H5T_VLEN)
1596             endRow = rows;
1597         if (lines == -1 && dclass != H5T_VLEN)
1598             lines = endRow;
1599         actualRows = endRow - startRow + 1;
1600         actualCols = 1; // data is only one column (if not VLEN)
1601 #ifndef NDEBUG
1602         H5T_order_t order = H5Tget_order(dtype);
1603         handleError((int)order, QStringLiteral("H5Sget_order"));
1604 #endif
1605         QDEBUG(Q_FUNC_INFO << ": " << translateHDF5Class(dclass) << '(' << typeSize << ')' << translateHDF5Order(order) << ", rows:" << rows
1606                            << " max:" << maxSize);
1607 
1608         QVector<AbstractColumn::ColumnMode> columnModes;
1609         columnModes.resize(actualCols);
1610         // set other modes
1611         if (dclass == H5T_STRING)
1612             for (auto& mode : columnModes)
1613                 mode = AbstractColumn::ColumnMode::Text;
1614         else if (dclass == H5T_INTEGER) {
1615             if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG) || H5Tequal(dtype, H5T_STD_U64LE)
1616                 || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG))
1617                 for (auto& mode : columnModes)
1618                     mode = AbstractColumn::ColumnMode::BigInt;
1619             else
1620                 for (auto& mode : columnModes)
1621                     mode = AbstractColumn::ColumnMode::Integer;
1622         }
1623 
1624         // use current data set name (without path) for column name
1625         QStringList vectorNames = {currentDataSetName.mid(currentDataSetName.lastIndexOf(QLatin1Char('/')) + 1)};
1626         QDEBUG(Q_FUNC_INFO << ", vector names = " << vectorNames)
1627 
1628         if (dataSource && dclass != H5T_VLEN && dclass != H5T_COMPOUND)
1629             columnOffset = dataSource->prepareImport(dataContainer, mode, actualRows, actualCols, vectorNames, columnModes);
1630 
1631         QStringList dataString; // data saved in a list
1632         switch (dclass) {
1633         case H5T_STRING: {
1634             DEBUG("rank 1 H5T_STRING");
1635             hid_t memtype = H5Tcopy(H5T_C_S1);
1636             handleError((int)memtype, QStringLiteral("H5Tcopy"));
1637 
1638             char** data = (char**)malloc(rows * sizeof(char*));
1639 
1640             if (H5Tis_variable_str(dtype)) {
1641                 m_status = H5Tset_size(memtype, H5T_VARIABLE);
1642                 handleError((int)memtype, QStringLiteral("H5Tset_size"));
1643                 m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
1644                 handleError(m_status, QStringLiteral("H5Dread"));
1645             } else {
1646                 data[0] = (char*)malloc(rows * typeSize * sizeof(char));
1647                 for (int i = 1; i < rows; ++i)
1648                     data[i] = data[0] + i * typeSize;
1649 
1650                 m_status = H5Tset_size(memtype, typeSize);
1651                 handleError((int)memtype, QStringLiteral("H5Tset_size"));
1652 
1653                 m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data[0]);
1654                 handleError(m_status, QStringLiteral("H5Dread"));
1655             }
1656 
1657             for (int i = startRow - 1; i < std::min(endRow, lines + startRow - 1); ++i)
1658                 dataString << QLatin1String(data[i]);
1659 
1660             free(data);
1661             break;
1662         }
1663         case H5T_INTEGER: {
1664             if (H5Tequal(dtype, H5T_STD_I8LE) || H5Tequal(dtype, H5T_STD_I8BE))
1665                 dataString = readHDF5Data1D<qint8>(dataset, dtype, rows, lines, dataContainer[0]);
1666             else if (H5Tequal(dtype, H5T_STD_U8LE) || H5Tequal(dtype, H5T_STD_U8BE))
1667                 dataString = readHDF5Data1D<uint8_t>(dataset, dtype, rows, lines, dataContainer[0]);
1668             else if (H5Tequal(dtype, H5T_NATIVE_CHAR)) {
1669                 switch (sizeof(H5T_NATIVE_CHAR)) {
1670                 case 1:
1671                     dataString = readHDF5Data1D<qint8>(dataset, dtype, rows, lines, dataContainer[0]);
1672                     break;
1673                 case 2:
1674                     dataString = readHDF5Data1D<qint16>(dataset, dtype, rows, lines, dataContainer[0]);
1675                     break;
1676                 case 4:
1677                     dataString = readHDF5Data1D<qint32>(dataset, dtype, rows, lines, dataContainer[0]);
1678                     break;
1679                 case 8:
1680                     dataString = readHDF5Data1D<qint64>(dataset, dtype, rows, lines, dataContainer[0]);
1681                     break;
1682                 }
1683             } else if (H5Tequal(dtype, H5T_NATIVE_UCHAR)) {
1684                 switch (sizeof(H5T_NATIVE_UCHAR)) {
1685                 case 1:
1686                     dataString = readHDF5Data1D<uint8_t>(dataset, dtype, rows, lines, dataContainer[0]);
1687                     break;
1688                 case 2:
1689                     dataString = readHDF5Data1D<uint16_t>(dataset, dtype, rows, lines, dataContainer[0]);
1690                     break;
1691                 case 4:
1692                     dataString = readHDF5Data1D<uint32_t>(dataset, dtype, rows, lines, dataContainer[0]);
1693                     break;
1694                 case 8:
1695                     dataString = readHDF5Data1D<uint64_t>(dataset, dtype, rows, lines, dataContainer[0]);
1696                     break;
1697                 }
1698             } else if (H5Tequal(dtype, H5T_STD_I16LE) || H5Tequal(dtype, H5T_STD_I16BE) || H5Tequal(dtype, H5T_NATIVE_SHORT))
1699                 dataString = readHDF5Data1D<short>(dataset, dtype, rows, lines, dataContainer[0]);
1700             else if (H5Tequal(dtype, H5T_STD_U16LE) || H5Tequal(dtype, H5T_STD_U16BE) || H5Tequal(dtype, H5T_NATIVE_USHORT))
1701                 dataString = readHDF5Data1D<unsigned short>(dataset, dtype, rows, lines, dataContainer[0]);
1702             else if (H5Tequal(dtype, H5T_STD_I32LE) || H5Tequal(dtype, H5T_STD_I32BE) || H5Tequal(dtype, H5T_NATIVE_INT))
1703                 dataString = readHDF5Data1D<int>(dataset, dtype, rows, lines, dataContainer[0]);
1704             else if (H5Tequal(dtype, H5T_STD_U32LE) || H5Tequal(dtype, H5T_STD_U32BE) || H5Tequal(dtype, H5T_NATIVE_UINT))
1705                 dataString = readHDF5Data1D<unsigned int>(dataset, dtype, rows, lines, dataContainer[0]);
1706             else if (H5Tequal(dtype, H5T_NATIVE_LONG))
1707                 dataString = readHDF5Data1D<long>(dataset, dtype, rows, lines, dataContainer[0]);
1708             else if (H5Tequal(dtype, H5T_NATIVE_ULONG))
1709                 dataString = readHDF5Data1D<unsigned long>(dataset, dtype, rows, lines, dataContainer[0]);
1710             else if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG))
1711                 dataString = readHDF5Data1D<long long>(dataset, dtype, rows, lines, dataContainer[0]);
1712             else if (H5Tequal(dtype, H5T_STD_U64LE) || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG))
1713                 dataString = readHDF5Data1D<unsigned long long>(dataset, dtype, rows, lines, dataContainer[0]);
1714             else {
1715                 ok = false;
1716                 dataString = (QStringList() << i18n("unsupported integer type for rank 1"));
1717                 QDEBUG(dataString);
1718             }
1719             break;
1720         }
1721         case H5T_FLOAT: {
1722             if (H5Tequal(dtype, H5T_IEEE_F32LE) || H5Tequal(dtype, H5T_IEEE_F32BE))
1723                 dataString = readHDF5Data1D<float>(dataset, H5T_NATIVE_FLOAT, rows, lines, dataContainer[0]);
1724             else if (H5Tequal(dtype, H5T_IEEE_F64LE) || H5Tequal(dtype, H5T_IEEE_F64BE))
1725                 dataString = readHDF5Data1D<double>(dataset, H5T_NATIVE_DOUBLE, rows, lines, dataContainer[0]);
1726             else if (H5Tequal(dtype, H5T_NATIVE_LDOUBLE))
1727                 dataString = readHDF5Data1D<long double>(dataset, H5T_NATIVE_LDOUBLE, rows, lines, dataContainer[0]);
1728             else {
1729                 ok = false;
1730                 dataString = (QStringList() << i18n("unsupported float type for rank 1"));
1731                 QDEBUG(dataString);
1732             }
1733             break;
1734         }
1735         case H5T_COMPOUND: {
1736             int members = H5Tget_nmembers(dtype);
1737             handleError(members, QStringLiteral("H5Tget_nmembers"));
1738             DEBUG(Q_FUNC_INFO << ", COMPOUND type. members: " << members)
1739             columnModes.resize(members);
1740             if (dataSource) // create data pointer here
1741                 dataSource->prepareImport(dataContainer, mode, actualRows, members, vectorNames, columnModes);
1742             else
1743                 dataStrings << readHDF5Compound(dtype);
1744             dataString = readHDF5CompoundData1D(dataset, dtype, rows, lines, dataContainer);
1745             break;
1746         }
1747         case H5T_VLEN: {
1748             DEBUG("H5T_VLEN")
1749             if (endColumn == -1)
1750                 endColumn = size;
1751             actualCols = endColumn - startColumn + 1;
1752             DEBUG("size = " << size << ", actual cols = " << actualCols << ", rows/lines = " << rows << "/" << lines)
1753 
1754             // set column mode
1755             hid_t base_type = H5Tget_super(dtype);
1756             columnModes.resize(actualCols);
1757             for (auto& mode : columnModes)
1758                 mode = HDF5FilterPrivate::translateHDF5TypeToMode(base_type);
1759 
1760             hvl_t* rdata = (hvl_t*)malloc(size * sizeof(hvl_t));
1761             hid_t memtype = H5Tvlen_create(base_type);
1762             m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata);
1763 
1764             size_t maxLength = 0;
1765             for (int c = startColumn - 1; c < endColumn; c++) // columns
1766                 maxLength = std::max(maxLength, rdata[c].len);
1767             if (endRow == -1 || endRow > (int)maxLength)
1768                 endRow = maxLength;
1769             actualRows = endRow - startRow + 1;
1770             if (lines == -1 || lines > actualRows)
1771                 lines = actualRows;
1772             dataStrings.resize(std::min(lines, actualRows));
1773 
1774             DEBUG("start/end row = " << startRow << "/" << endRow << ", lines = " << lines << ", max length = " << maxLength)
1775             DEBUG("start/end col = " << startColumn << "/" << endColumn)
1776             DEBUG("actual rows/cols = " << actualRows << " " << actualCols)
1777             if (dataSource) {
1778                 if (size > 1) { // set vectorNames
1779                     const QString datasetName = vectorNames.at(0);
1780                     vectorNames.clear();
1781                     for (int i = startColumn; i <= endColumn; i++)
1782                         vectorNames << datasetName + QStringLiteral("_") + QString::number(i);
1783                 }
1784                 // create data pointer here
1785                 dataSource->prepareImport(dataContainer, mode, actualRows, actualCols, vectorNames, columnModes);
1786             }
1787 
1788             for (int c = startColumn - 1; c < endColumn; c++) { // columns
1789                 int length = rdata[c].len;
1790                 // DEBUG("length = " << length)
1791                 /*for (hsize_t j = 0; j < length; j++) {
1792                     printf (" %d", data[j]);
1793                     if ((j+1) < length)
1794                         printf (",");
1795                 }
1796                 printf (" }\n");*/
1797                 // read column
1798                 if (H5Tequal(base_type, H5T_STD_I8LE) || H5Tequal(base_type, H5T_STD_I8BE))
1799                     HDF5_READ_VLEN_1D(qint8, int)
1800                 else if (H5Tequal(base_type, H5T_STD_U8LE) || H5Tequal(base_type, H5T_STD_U8BE))
1801                     HDF5_READ_VLEN_1D(quint8, int)
1802                 else if (H5Tequal(base_type, H5T_NATIVE_CHAR)) {
1803                     switch (sizeof(H5T_NATIVE_CHAR)) {
1804                     case 1:
1805                         HDF5_READ_VLEN_1D(qint8, int)
1806                         break;
1807                     case 2:
1808                         HDF5_READ_VLEN_1D(qint16, int)
1809                         break;
1810                     case 4:
1811                         HDF5_READ_VLEN_1D(qint32, int)
1812                         break;
1813                     case 8:
1814                         HDF5_READ_VLEN_1D(qint64, qint64)
1815                         break;
1816                     }
1817                 } else if (H5Tequal(base_type, H5T_NATIVE_UCHAR)) {
1818                     switch (sizeof(H5T_NATIVE_UCHAR)) {
1819                     case 1:
1820                         HDF5_READ_VLEN_1D(quint8, int)
1821                         break;
1822                     case 2:
1823                         HDF5_READ_VLEN_1D(quint16, int)
1824                         break;
1825                     case 4:
1826                         HDF5_READ_VLEN_1D(quint32, int)
1827                         break;
1828                     case 8:
1829                         HDF5_READ_VLEN_1D(quint64, qint64)
1830                         break;
1831                     }
1832                 } else if (H5Tequal(base_type, H5T_STD_I16LE) || H5Tequal(base_type, H5T_STD_I16BE) || H5Tequal(base_type, H5T_NATIVE_SHORT))
1833                     HDF5_READ_VLEN_1D(qint16, int)
1834                 else if (H5Tequal(base_type, H5T_STD_U16LE) || H5Tequal(base_type, H5T_STD_U16BE) || H5Tequal(base_type, H5T_NATIVE_USHORT))
1835                     HDF5_READ_VLEN_1D(quint16, int)
1836                 else if (H5Tequal(base_type, H5T_STD_I32LE) || H5Tequal(base_type, H5T_STD_I32BE) || H5Tequal(base_type, H5T_NATIVE_INT))
1837                     HDF5_READ_VLEN_1D(qint32, int)
1838                 else if (H5Tequal(base_type, H5T_STD_U32LE) || H5Tequal(base_type, H5T_STD_U32BE) || H5Tequal(base_type, H5T_NATIVE_UINT))
1839                     HDF5_READ_VLEN_1D(quint32, qint64)
1840                 else if (H5Tequal(base_type, H5T_NATIVE_LONG))
1841                     HDF5_READ_VLEN_1D(long, qint64)
1842                 else if (H5Tequal(base_type, H5T_NATIVE_ULONG))
1843                     HDF5_READ_VLEN_1D(unsigned long, qint64)
1844                 else if (H5Tequal(base_type, H5T_STD_I64LE) || H5Tequal(base_type, H5T_STD_I64BE) || H5Tequal(base_type, H5T_NATIVE_LLONG))
1845                     HDF5_READ_VLEN_1D(qint64, qint64)
1846                 else if (H5Tequal(base_type, H5T_STD_U64LE) || H5Tequal(base_type, H5T_STD_U64BE) || H5Tequal(base_type, H5T_NATIVE_ULLONG))
1847                     HDF5_READ_VLEN_1D(quint64, qint64)
1848                 else if (H5Tequal(base_type, H5T_IEEE_F32LE) || H5Tequal(base_type, H5T_IEEE_F32BE))
1849                     HDF5_READ_VLEN_1D(float, double)
1850                 else if (H5Tequal(base_type, H5T_IEEE_F64LE) || H5Tequal(base_type, H5T_IEEE_F64BE))
1851                     HDF5_READ_VLEN_1D(double, double)
1852                 else if (H5Tequal(base_type, H5T_NATIVE_LDOUBLE))
1853                     HDF5_READ_VLEN_1D(double, double) // long double not supported from QString::number
1854                 else {
1855                     dataString = (QStringList() << i18n("unsupported integer type for rank 1"));
1856                     QDEBUG(dataString);
1857                 }
1858             }
1859 
1860             free(rdata);
1861             break;
1862         }
1863         case H5T_TIME:
1864         case H5T_BITFIELD:
1865         case H5T_OPAQUE:
1866         case H5T_REFERENCE:
1867         case H5T_ENUM:
1868         case H5T_ARRAY:
1869         case H5T_NO_CLASS:
1870         case H5T_NCLASSES: {
1871             ok = false;
1872             dataString = (QStringList() << i18n("rank 1 not implemented yet for type %1", translateHDF5Class(dclass)));
1873             QDEBUG(dataString);
1874         }
1875         default:
1876             break;
1877         }
1878 
1879         if (!dataSource && dclass != H5T_VLEN) { // preview (VLEN is special)
1880             QDEBUG("dataString =" << dataString);
1881             DEBUG(" data string size = " << dataString.size());
1882             DEBUG(" rows = " << rows << ", lines = " << lines << ", actual rows = " << actualRows);
1883             for (int i = 0; i < std::min(actualRows, lines); ++i)
1884                 dataStrings << (QStringList() << dataString[i]);
1885         }
1886 
1887         break;
1888     }
1889     case 2: { // 2D data
1890         hsize_t dims_out[2];
1891         m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr);
1892         handleError(m_status, QStringLiteral("H5Sget_simple_extent_dims"));
1893         int rows = dims_out[0];
1894         int cols = dims_out[1];
1895 
1896         if (endRow == -1)
1897             endRow = rows;
1898         if (lines == -1)
1899             lines = endRow;
1900         if (endColumn == -1)
1901             endColumn = cols;
1902         actualRows = endRow - startRow + 1;
1903         actualCols = endColumn - startColumn + 1;
1904 
1905 #ifndef NDEBUG
1906         H5T_order_t order = H5Tget_order(dtype);
1907         handleError((int)order, QStringLiteral("H5Tget_order"));
1908 #endif
1909         // QDEBUG(translateHDF5Class(dclass) << '(' << typeSize << ')' << translateHDF5Order(order) << "," << rows << "x" << cols);
1910         DEBUG(Q_FUNC_INFO << ", start/end row = " << startRow << "/" << endRow);
1911         DEBUG(Q_FUNC_INFO << ", start/end column = " << startColumn << "/" << endColumn);
1912         DEBUG(Q_FUNC_INFO << ", actual rows/cols = " << actualRows << "/" << actualCols);
1913         DEBUG(Q_FUNC_INFO << ", lines = " << lines);
1914 
1915         QVector<AbstractColumn::ColumnMode> columnModes;
1916         columnModes.resize(actualCols);
1917         // set other modes
1918         if (dclass == H5T_STRING)
1919             for (auto& mode : columnModes)
1920                 mode = AbstractColumn::ColumnMode::Text;
1921         else if (dclass == H5T_INTEGER) {
1922             if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG) || H5Tequal(dtype, H5T_STD_U64LE)
1923                 || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG))
1924                 for (auto& mode : columnModes)
1925                     mode = AbstractColumn::ColumnMode::BigInt;
1926             else
1927                 for (auto& mode : columnModes)
1928                     mode = AbstractColumn::ColumnMode::Integer;
1929         }
1930 
1931         // use current data set name (without path) append by "_" and column number for column names
1932         QStringList vectorNames;
1933         QString colName = currentDataSetName.mid(currentDataSetName.lastIndexOf(QLatin1Char('/')) + 1);
1934         for (int i = 0; i < actualCols; i++)
1935             vectorNames << colName + QLatin1String("_") + QString::number(i + 1);
1936         QDEBUG(Q_FUNC_INFO << ", vector names = " << vectorNames)
1937 
1938         if (dataSource)
1939             columnOffset = dataSource->prepareImport(dataContainer, mode, actualRows, actualCols, vectorNames, columnModes);
1940 
1941         // read data
1942         switch (dclass) {
1943         case H5T_INTEGER: {
1944             if (H5Tequal(dtype, H5T_STD_I8LE))
1945                 dataStrings << readHDF5Data2D<qint8>(dataset, H5T_STD_I8LE, rows, cols, lines, dataContainer);
1946             else if (H5Tequal(dtype, H5T_STD_I8BE))
1947                 dataStrings << readHDF5Data2D<qint8>(dataset, H5T_STD_I8BE, rows, cols, lines, dataContainer);
1948             else if (H5Tequal(dtype, H5T_NATIVE_CHAR)) {
1949                 switch (sizeof(H5T_NATIVE_CHAR)) {
1950                 case 1:
1951                     dataStrings << readHDF5Data2D<qint8>(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer);
1952                     break;
1953                 case 2:
1954                     dataStrings << readHDF5Data2D<qint16>(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer);
1955                     break;
1956                 case 4:
1957                     dataStrings << readHDF5Data2D<qint32>(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer);
1958                     break;
1959                 case 8:
1960                     dataStrings << readHDF5Data2D<qint64>(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer);
1961                     break;
1962                 }
1963             } else if (H5Tequal(dtype, H5T_STD_U8LE))
1964                 dataStrings << readHDF5Data2D<uint8_t>(dataset, H5T_STD_U8LE, rows, cols, lines, dataContainer);
1965             else if (H5Tequal(dtype, H5T_STD_U8BE))
1966                 dataStrings << readHDF5Data2D<uint8_t>(dataset, H5T_STD_U8BE, rows, cols, lines, dataContainer);
1967             else if (H5Tequal(dtype, H5T_NATIVE_UCHAR)) {
1968                 switch (sizeof(H5T_NATIVE_UCHAR)) {
1969                 case 1:
1970                     dataStrings << readHDF5Data2D<uint8_t>(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer);
1971                     break;
1972                 case 2:
1973                     dataStrings << readHDF5Data2D<uint16_t>(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer);
1974                     break;
1975                 case 4:
1976                     dataStrings << readHDF5Data2D<uint32_t>(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer);
1977                     break;
1978                 case 8:
1979                     dataStrings << readHDF5Data2D<uint64_t>(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer);
1980                     break;
1981                 }
1982             } else if (H5Tequal(dtype, H5T_STD_I16LE) || H5Tequal(dtype, H5T_STD_I16BE) || H5Tequal(dtype, H5T_NATIVE_SHORT))
1983                 dataStrings << readHDF5Data2D<short>(dataset, H5T_NATIVE_SHORT, rows, cols, lines, dataContainer);
1984             else if (H5Tequal(dtype, H5T_STD_U16LE) || H5Tequal(dtype, H5T_STD_U16BE) || H5Tequal(dtype, H5T_NATIVE_USHORT))
1985                 dataStrings << readHDF5Data2D<unsigned short>(dataset, H5T_NATIVE_USHORT, rows, cols, lines, dataContainer);
1986             else if (H5Tequal(dtype, H5T_STD_I32LE) || H5Tequal(dtype, H5T_STD_I32BE) || H5Tequal(dtype, H5T_NATIVE_INT))
1987                 dataStrings << readHDF5Data2D<int>(dataset, H5T_NATIVE_INT, rows, cols, lines, dataContainer);
1988             else if (H5Tequal(dtype, H5T_STD_U32LE) || H5Tequal(dtype, H5T_STD_U32BE) || H5Tequal(dtype, H5T_NATIVE_UINT))
1989                 dataStrings << readHDF5Data2D<unsigned int>(dataset, H5T_NATIVE_UINT, rows, cols, lines, dataContainer);
1990             else if (H5Tequal(dtype, H5T_NATIVE_LONG))
1991                 dataStrings << readHDF5Data2D<long>(dataset, H5T_NATIVE_LONG, rows, cols, lines, dataContainer);
1992             else if (H5Tequal(dtype, H5T_NATIVE_ULONG))
1993                 dataStrings << readHDF5Data2D<unsigned long>(dataset, H5T_NATIVE_ULONG, rows, cols, lines, dataContainer);
1994             else if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG))
1995                 dataStrings << readHDF5Data2D<long long>(dataset, H5T_NATIVE_LLONG, rows, cols, lines, dataContainer);
1996             else if (H5Tequal(dtype, H5T_STD_U64LE) || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG))
1997                 dataStrings << readHDF5Data2D<unsigned long long>(dataset, H5T_NATIVE_ULLONG, rows, cols, lines, dataContainer);
1998             else {
1999                 ok = false;
2000                 dataStrings << (QStringList() << i18n("unsupported integer type for rank 2"));
2001                 // QDEBUG(dataStrings);
2002             }
2003             break;
2004         }
2005         case H5T_FLOAT: {
2006             if (H5Tequal(dtype, H5T_IEEE_F32LE) || H5Tequal(dtype, H5T_IEEE_F32BE))
2007                 dataStrings << readHDF5Data2D<float>(dataset, H5T_NATIVE_FLOAT, rows, cols, lines, dataContainer);
2008             else if (H5Tequal(dtype, H5T_IEEE_F64LE) || H5Tequal(dtype, H5T_IEEE_F64BE))
2009                 dataStrings << readHDF5Data2D<double>(dataset, H5T_NATIVE_DOUBLE, rows, cols, lines, dataContainer);
2010             else if (H5Tequal(dtype, H5T_NATIVE_LDOUBLE))
2011                 dataStrings << readHDF5Data2D<long double>(dataset, H5T_NATIVE_LDOUBLE, rows, cols, lines, dataContainer);
2012             else {
2013                 ok = false;
2014                 dataStrings << (QStringList() << i18n("unsupported float type for rank 2"));
2015                 QDEBUG(dataStrings);
2016             }
2017             break;
2018         }
2019         case H5T_COMPOUND: {
2020             dataStrings << readHDF5Compound(dtype);
2021             // QDEBUG(dataStrings);
2022             dataStrings << readHDF5CompoundData2D(dataset, dtype, rows, cols, lines);
2023             break;
2024         }
2025         case H5T_STRING: {
2026             DEBUG("rank 2 H5T_STRING");
2027             hid_t memtype = H5Tcopy(H5T_C_S1);
2028             handleError((int)memtype, QStringLiteral("H5Tcopy"));
2029 
2030             char** data = (char**)malloc(rows * cols * sizeof(char*));
2031 
2032             if (H5Tis_variable_str(dtype)) {
2033                 m_status = H5Tset_size(memtype, H5T_VARIABLE);
2034                 handleError((int)memtype, QStringLiteral("H5Tset_size"));
2035                 m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);
2036                 handleError(m_status, QStringLiteral("H5Dread"));
2037             } else {
2038                 data[0] = (char*)malloc(rows * cols * typeSize * sizeof(char));
2039                 for (int i = 1; i < rows * cols; ++i)
2040                     data[i] = data[0] + i * typeSize;
2041 
2042                 m_status = H5Tset_size(memtype, typeSize);
2043                 handleError((int)memtype, QStringLiteral("H5Tset_size"));
2044 
2045                 m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data[0]);
2046                 handleError(m_status, QStringLiteral("H5Dread"));
2047             }
2048 
2049             if (dataSource) {
2050                 for (int i = 0; i < actualRows; ++i) {
2051                     for (int j = 0; j < actualCols; ++j) {
2052                         static_cast<QVector<QString>*>(dataContainer[(int)(j)])->operator[](i) =
2053                             QLatin1String(data[(j + startColumn - 1) + (i + startRow - 1) * cols]);
2054                     }
2055                 }
2056             } else {
2057                 for (int i = startRow - 1; i < std::min(endRow, lines + startRow - 1); ++i) {
2058                     QStringList row;
2059                     for (int j = startColumn - 1; j < endColumn; ++j)
2060                         row << QLatin1String(data[j + i * cols]);
2061                     dataStrings << row;
2062                 }
2063             }
2064 
2065             free(data);
2066             break;
2067         }
2068         case H5T_TIME:
2069         case H5T_BITFIELD:
2070         case H5T_OPAQUE:
2071         case H5T_REFERENCE:
2072         case H5T_ENUM:
2073         case H5T_VLEN:
2074         case H5T_ARRAY:
2075         case H5T_NO_CLASS:
2076         case H5T_NCLASSES: {
2077             ok = false;
2078             dataStrings << (QStringList() << i18n("rank 2 not implemented yet for type %1", translateHDF5Class(dclass)));
2079             QDEBUG(dataStrings);
2080         }
2081         default:
2082             break;
2083         }
2084         break;
2085     }
2086     default: { // 3D or higher dim data
2087         ok = false;
2088         dataStrings << (QStringList() << i18n("rank %1 not implemented yet for type %2", rank, translateHDF5Class(dclass)));
2089         QDEBUG(dataStrings);
2090     }
2091     }
2092 
2093     m_status = H5Sclose(dataspace);
2094     handleError(m_status, QStringLiteral("H5Sclose"));
2095     m_status = H5Tclose(dtype);
2096     handleError(m_status, QStringLiteral("H5Tclose"));
2097     m_status = H5Dclose(dataset);
2098     handleError(m_status, QStringLiteral("H5Dclose"));
2099     m_status = H5Fclose(file);
2100     handleError(m_status, QStringLiteral("H5Fclose"));
2101 
2102     if (!dataSource)
2103         return dataStrings;
2104 
2105     DEBUG(Q_FUNC_INFO << ", finalize : actual cols = " << actualCols)
2106     dataSource->finalizeImport(columnOffset, 1, actualCols, QString(), mode);
2107 #else
2108     Q_UNUSED(fileName)
2109     Q_UNUSED(dataSource)
2110     Q_UNUSED(mode)
2111     Q_UNUSED(lines)
2112 #endif
2113 
2114     return dataStrings;
2115 }
2116 
2117 /*!
2118     reads the content of the file \c fileName to the data source \c dataSource.
2119     Uses the settings defined in the data source.
2120 */
2121 void HDF5FilterPrivate::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode) {
2122     DEBUG(Q_FUNC_INFO);
2123 
2124     if (currentDataSetName.isEmpty()) {
2125         DEBUG("WARNING: No data set selected");
2126         return;
2127     }
2128 
2129     bool ok = true;
2130     readCurrentDataSet(fileName, dataSource, ok, mode);
2131 }
2132 
2133 /*!
2134     writes the content of \c dataSource to the file \c fileName.
2135 */
2136 void HDF5FilterPrivate::write(const QString& /*fileName*/, AbstractDataSource* /*dataSource*/) {
2137     // TODO: writing HDF5 not implemented yet
2138 }
2139 
2140 // ##############################################################################
2141 // ##################  Serialization/Deserialization  ###########################
2142 // ##############################################################################
2143 
2144 /*!
2145   Saves as XML.
2146  */
2147 void HDF5Filter::save(QXmlStreamWriter* writer) const {
2148     writer->writeStartElement(QStringLiteral("hdfFilter"));
2149     writer->writeEndElement();
2150 }
2151 
2152 /*!
2153   Loads from XML.
2154 */
2155 bool HDF5Filter::load(XmlStreamReader*) {
2156     return true;
2157 }