File indexing completed on 2024-12-22 04:17:13

0001 /***************************************************************************
0002                  dirfile.cpp  -  data source for dirfiles
0003                              -------------------
0004     begin                : Tue Oct 21 2003
0005     copyright            : (C) 2003 The University of Toronto
0006     email                : netterfield@astro.utoronto.ca
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include "dirfilesource.h"
0019 
0020 
0021 #include <QXmlStreamWriter>
0022 #include <QFileSystemWatcher>
0023 #include <QDir>
0024 
0025 using namespace Kst;
0026 
0027 static const QString dirfileTypeString = "Directory of Binary Files";
0028 
0029 class DirFileSource::Config {
0030   public:
0031     Config() {
0032     }
0033 
0034     void read(QSettings *cfg, const QString& fileName = QString()) {
0035       Q_UNUSED(fileName);
0036       cfg->beginGroup(dirfileTypeString);
0037       cfg->endGroup();
0038     }
0039 
0040     void save(QXmlStreamWriter& s) {
0041       Q_UNUSED(s);
0042     }
0043 
0044     void load(const QDomElement& e) {
0045       Q_UNUSED(e);
0046     }
0047 };
0048 
0049 //
0050 // Scalar Interface
0051 //
0052 class DataInterfaceDirFileScalar : public DataSource::DataInterface<DataScalar>
0053 {
0054 public:
0055   DataInterfaceDirFileScalar(DirFileSource& d) : dir(d) {}
0056 
0057   // read one element
0058   int read(const QString&, DataScalar::ReadInfo&);
0059 
0060   // named elements
0061   QStringList list() const { return dir._scalarList; }
0062   bool isListComplete() const { return true; }
0063   bool isValid(const QString& field) const { return dir._scalarList.contains( field ); }
0064 
0065   // T specific: not used for scalars
0066   const DataScalar::DataInfo dataInfo(const QString&, int frame = 0) const { Q_UNUSED(frame) return DataScalar::DataInfo(); }
0067   void setDataInfo(const QString&, const DataScalar::DataInfo&) {}
0068 
0069   // meta data
0070   QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); }
0071   QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); }
0072 
0073 
0074   DirFileSource& dir;
0075 };
0076 
0077 int DataInterfaceDirFileScalar::read(const QString& field, DataScalar::ReadInfo& p)
0078 {
0079   return dir.readScalar(*p.value, field);
0080 }
0081 
0082 //
0083 // String Interface
0084 //
0085 class DataInterfaceDirFileString : public DataSource::DataInterface<DataString>
0086 {
0087 public:
0088   DataInterfaceDirFileString(DirFileSource& d) : dir(d) {}
0089 
0090   // read one element
0091   int read(const QString&, DataString::ReadInfo&);
0092 
0093   // named elements
0094   QStringList list() const { return dir._stringList; }
0095   bool isListComplete() const { return true; }
0096   bool isValid(const QString& field) const { return dir._stringList.contains( field ); }
0097 
0098   // T specific: not used for Strings
0099   virtual const DataString::DataInfo dataInfo(const QString&, int frame=0) const;
0100   void setDataInfo(const QString&, const DataString::DataInfo&) {}
0101 
0102   // meta data
0103   QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); }
0104   QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); }
0105 
0106 
0107   DirFileSource& dir;
0108 };
0109 
0110 int DataInterfaceDirFileString::read(const QString& field, DataString::ReadInfo& p)
0111 {
0112   if (dir.isStringStream(field)) {
0113     return dir.readSindir(*p.value, field, p.frame);
0114   } else {
0115     return dir.readString(*p.value, field);
0116   }
0117 }
0118 
0119 const DataString::DataInfo DataInterfaceDirFileString::dataInfo(const QString &, int frame) const
0120 {
0121   Q_UNUSED(frame)
0122 
0123   DataString::DataInfo info;
0124   info.frameCount = dir.frameCount();
0125 
0126   return info;
0127 }
0128 
0129 
0130 //
0131 // Vector interface
0132 //
0133 
0134 class DataInterfaceDirFileVector : public DataSource::DataInterface<DataVector>
0135 {
0136 public:
0137   DataInterfaceDirFileVector(DirFileSource& d) : dir(d) {}
0138 
0139   // read one element
0140   int read(const QString&, DataVector::ReadInfo&);
0141 
0142   // named elements
0143   QStringList list() const { return dir._fieldList; }
0144   bool isListComplete() const { return true; }
0145   bool isValid(const QString& field) const { return dir._fieldList.contains( field ); }
0146 
0147   // T specific
0148   const DataVector::DataInfo dataInfo(const QString&, int frame = 0) const;
0149   void setDataInfo(const QString&, const DataVector::DataInfo&) {}
0150 
0151   // meta data
0152   QMap<QString, double> metaScalars(const QString&);
0153   QMap<QString, QString> metaStrings(const QString&);
0154 
0155 
0156   DirFileSource& dir;
0157 };
0158 
0159 
0160 
0161 const DataVector::DataInfo DataInterfaceDirFileVector::dataInfo(const QString &field, int frame) const
0162 {
0163   Q_UNUSED(frame)
0164   if (!dir._fieldList.contains(field))
0165     return DataVector::DataInfo();
0166 
0167   return DataVector::DataInfo(dir._frameCount, dir.samplesPerFrame(field));
0168 }
0169 
0170 
0171 int DataInterfaceDirFileVector::read(const QString& field, DataVector::ReadInfo& p)
0172 {
0173   return dir.readField(p.data, field, p.startingFrame, p.numberOfFrames);
0174 }
0175 
0176 
0177 QMap<QString, double> DataInterfaceDirFileVector::metaScalars(const QString& field)
0178 {
0179   QStringList keys = dir.fieldScalars(field);
0180   QList<double> values;
0181   int scalars = dir.readFieldScalars(values, field, true);
0182   QMap<QString, double> m;
0183   for (int i = 0; i < scalars; i++) {
0184     if (values.size() > i && keys.size() > i)
0185       m[keys.at(i)] = values.at(i);
0186   }
0187   return m;
0188 }
0189 
0190 
0191 QMap<QString, QString> DataInterfaceDirFileVector::metaStrings(const QString& field)
0192 {
0193   QStringList keys = dir.fieldStrings(field);
0194   QStringList values;
0195   int strings = dir.readFieldStrings(values, field, true);
0196   QMap<QString, QString> m;
0197   for (int i = 0; i < strings; i++) {
0198     if (values.size() > i && keys.size() > i)
0199       m[keys.at(i)] = values.at(i);
0200   }
0201   return m;
0202 }
0203 
0204 //
0205 // DirFileSource
0206 //
0207 
0208 DirFileSource::DirFileSource(Kst::ObjectStore *store, QSettings *cfg, const QString& filename, const QString& type, const QDomElement& e) :
0209     Kst::DataSource(store, cfg, filename, type), _config(0L),
0210   iv(new DataInterfaceDirFileVector(*this)), ix(new DataInterfaceDirFileScalar(*this)),
0211   is(new DataInterfaceDirFileString(*this)), _resetNeeded(false)
0212 {
0213   setInterface(iv);
0214   setInterface(ix);
0215   setInterface(is);
0216 
0217   setUpdateType(None);
0218 
0219   _valid = false;
0220   if (!type.isEmpty() && type != dirfileTypeString) {
0221     return;
0222   }
0223 
0224   _config = new DirFileSource::Config;
0225   _config->read(cfg, _filename);
0226   if (!e.isNull()) {
0227     _config->load(e);
0228   }
0229 
0230   _valid = true;
0231   _directoryName = DirFilePlugin::getDirectory(_filename);
0232 
0233   init();
0234   registerChange();
0235 
0236 }
0237 
0238 
0239 
0240 DirFileSource::~DirFileSource()
0241 {
0242   delete _config;
0243   _config = 0L;
0244   delete _dirfile;
0245   _dirfile = 0L;
0246 }
0247 
0248 
0249 void DirFileSource::reset()
0250 {
0251   resetFileWatcher();
0252   if (_dirfile) {
0253     delete _dirfile;
0254   }
0255 
0256   init();
0257   Object::reset();
0258 }
0259 
0260 
0261 bool DirFileSource::init() {
0262   _fieldList.clear();
0263   _scalarList.clear();
0264   _stringList.clear();
0265   _sindirList.clear();
0266 
0267   _frameCount = 0;
0268 
0269   _dirfile = new Dirfile(_directoryName.toLatin1(), GD_RDONLY);
0270 
0271   if (_dirfile->Error() == GD_E_OK) {
0272 
0273     const char **vl = _dirfile->VectorList();
0274     for (int i = 0; vl[i]!=NULL; i++) {
0275       _fieldList.append(QString::fromUtf8(vl[i]));
0276     }
0277 
0278     _scalarList.append("FRAMES");
0279     const char **xl = _dirfile->FieldListByType(ConstEntryType);
0280     for (int i = 0; xl[i]!=NULL; i++) {
0281       _scalarList.append(QString::fromUtf8(xl[i]));
0282     }
0283 
0284     _stringList.append("FILE");
0285     const char **tl = _dirfile->FieldListByType(StringEntryType);
0286     for (int i = 0; tl[i]!=NULL; i++) {
0287       _stringList.append(QString::fromUtf8(tl[i]));
0288     }
0289 
0290     const char **nl = _dirfile->FieldListByType(SindirEntryType);
0291     for (int i = 0; nl[i]!=NULL; i++) {
0292       _sindirList.append(QString::fromUtf8(nl[i]));
0293       _stringList.append(QString::fromUtf8(nl[i])); // _stringList contains both
0294     }
0295 
0296     _writable = true;
0297     _frameCount = _dirfile->NFrames();
0298   }
0299 
0300   if (_fieldList.count() > 1) {
0301     QString filePath = _dirfile->ReferenceFilename();
0302   }
0303   setUpdateType(Timer);
0304 
0305   registerChange();
0306   return true;
0307 }
0308 
0309 
0310 Kst::Object::UpdateType DirFileSource::internalDataSourceUpdate() {
0311   int newNF = _dirfile->NFrames();
0312   bool isnew = newNF != _frameCount;
0313 
0314   _resetNeeded |= (_frameCount>newNF);
0315 
0316   _frameCount = newNF;
0317 
0318   if (_resetNeeded && newNF>0) {
0319     _resetNeeded = false;
0320     reset();
0321   }
0322   return (isnew ? Updated : NoChange);
0323 }
0324 
0325 int DirFileSource::readField(double *v, const QString& field, int s, int n) {
0326 
0327   if (n < 0) {
0328     return _dirfile->GetData(field.toUtf8().constData(),
0329                    s, 0, /* 1st sframe, 1st samp */
0330                    0, 1, /* num sframes, num samps */
0331                    Float64, (void*)v);
0332   } else {
0333     return _dirfile->GetData(field.toUtf8().constData(),
0334                    s, 0, /* 1st sframe, 1st samp */
0335                    n, 0, /* num sframes, num samps */
0336                    Float64, (void*)v);
0337   }
0338 }
0339 
0340 
0341 // int DirFileSource::writeField(const double *v, const QString& field, int s, int n) {
0342 //   int err = 0;
0343 //
0344 //   return PutData(_directoryName.toLatin1(), field.left(FIELD_LENGTH).toLatin1(),
0345 //       s, 0, /* 1st sframe, 1st samp */
0346 //       n, 0, /* num sframes, num samps */
0347 //       'd', (void*)v,
0348 //       &err);
0349 // }
0350 
0351 
0352 int DirFileSource::samplesPerFrame(const QString &field) {
0353   return int(_dirfile->SamplesPerFrame(field.toUtf8().constData()));
0354 }
0355 
0356 
0357 int DirFileSource::frameCount(const QString& field) const {
0358   Q_UNUSED(field)
0359   return _frameCount;
0360 }
0361 
0362 
0363 bool DirFileSource::isEmpty() const {
0364   return _frameCount < 1;
0365 }
0366 
0367 
0368 QString DirFileSource::fileType() const {
0369   return dirfileTypeString;
0370 }
0371 
0372 
0373 void DirFileSource::save(QXmlStreamWriter &streamWriter) {
0374   Kst::DataSource::save(streamWriter);
0375 }
0376 
0377 
0378 int DirFileSource::readScalar(double &S, const QString& scalar) {
0379   if (scalar == "FRAMES") {
0380     S = _frameCount;
0381     return 1;
0382   } else {
0383     _dirfile->GetConstant(scalar.toUtf8().constData(), Float64, (void *)&S);
0384     if (_dirfile->Error() == GD_E_OK) {
0385       return 1;
0386     }
0387   }
0388 
0389   return 0;
0390 }
0391 
0392 
0393 int DirFileSource::readString(QString &S, const QString& string) {
0394   if (string == "FILE") {
0395     S = _filename;
0396     return 1;
0397   } else {
0398     char tmpstr[4097];
0399     _dirfile->GetString(string.toUtf8().constData(), 4097, tmpstr);
0400     if (_dirfile->Error() == GD_E_OK) {
0401       S = QString::fromUtf8(tmpstr);
0402       return 1;
0403     }
0404   }
0405 
0406   return 0;
0407 }
0408 
0409 int DirFileSource::readSindir(QString &S, const QString &field, int frame) {
0410   const char *tmpstr[1];
0411 
0412   _dirfile->GetData(field.toUtf8().constData(), frame, 0, 0, 1, tmpstr);
0413   if (_dirfile->Error() == GD_E_OK) {
0414     S = QString::fromUtf8(tmpstr[0]);
0415     return 1;
0416   }
0417 
0418   return 0;
0419 }
0420 
0421 //QStringList fieldScalars(const QString& field);
0422 
0423 QStringList DirFileSource::fieldScalars(const QString& field) {
0424   const char **mflist = _dirfile->MFieldListByType(field.toAscii(), ConstEntryType);
0425   if (!mflist) {
0426     return QStringList();
0427   }
0428   QStringList scalars;
0429   for (int i=0; mflist[i]; i++) {
0430     scalars.append(mflist[i]);
0431   }
0432   return scalars;
0433 }
0434 
0435 int DirFileSource::readFieldScalars(QList<double> &v, const QString& field, bool init) {
0436   int nc=0;
0437   if (init) { // only update if we need to initialize.  Otherwise preserve old values.
0438     v.clear();
0439     nc = _dirfile->NMFieldsByType(field.toAscii(),ConstEntryType);
0440     double *vin = (double *)_dirfile->MConstants(field.toAscii(), Float64);
0441     for (int i=0; i<nc; i++) {
0442       v.append(vin[i]);
0443     }
0444   }
0445   return (nc);
0446 }
0447 
0448 
0449 QStringList DirFileSource::fieldStrings(const QString& field) {
0450   const char **mflist = _dirfile->MFieldListByType(field.toAscii(), StringEntryType);
0451   if (!mflist) {
0452     return QStringList();
0453   }
0454   QStringList strings;
0455   for (int i=0; mflist[i]; i++) {
0456     strings.append(mflist[i]);
0457   }
0458   return strings;
0459 }
0460 
0461 int DirFileSource::readFieldStrings(QStringList &v, const QString& field, bool init) {
0462   int nc=0;
0463   if (init) { // only update if we need to initialize.  Otherwise preserve old values.
0464     v.clear();
0465     nc = _dirfile->NMFieldsByType(field.toAscii(),StringEntryType);
0466     char **str_in = (char **)_dirfile->MStrings(field.toAscii());
0467     for (int i=0; i<nc; i++) {
0468       v.append(str_in[i]);
0469     }
0470   }
0471   return (nc);
0472 }
0473 
0474 
0475 QString DirFilePlugin::pluginName() const { return tr("DirFile Reader"); }
0476 QString DirFilePlugin::pluginDescription() const { return tr("DirFile Reader"); }
0477 
0478 
0479 Kst::DataSource *DirFilePlugin::create(Kst::ObjectStore *store,
0480                                             QSettings *cfg,
0481                                             const QString &filename,
0482                                             const QString &type,
0483                                             const QDomElement &element) const {
0484   return new DirFileSource(store, cfg, filename, type, element);
0485 }
0486 
0487 
0488 
0489 QStringList DirFilePlugin::matrixList(QSettings *cfg,
0490                                              const QString& filename,
0491                                              const QString& type,
0492                                              QString *typeSuggestion,
0493                                              bool *complete) const {
0494 
0495 
0496   if (typeSuggestion) {
0497     *typeSuggestion = dirfileTypeString;
0498   }
0499   if ((!type.isEmpty() && !provides().contains(type)) ||
0500       0 == understands(cfg, filename)) {
0501     if (complete) {
0502       *complete = false;
0503     }
0504     return QStringList();
0505   }
0506   return QStringList();
0507 }
0508 
0509 const QString& DirFileSource::typeString() const {
0510   return dirfileTypeString;
0511 }
0512 
0513 bool DirFileSource::isStringStream(QString field)
0514 {
0515   if (_sindirList.contains(field)) {
0516     return true;
0517   } else {
0518     return false;
0519   }
0520 }
0521 
0522 
0523 
0524 QStringList DirFilePlugin::scalarList(QSettings *cfg,
0525                                             const QString& filename,
0526                                             const QString& type,
0527                                             QString *typeSuggestion,
0528                                             bool *complete) const {
0529 
0530   Q_UNUSED(cfg);
0531   Q_UNUSED(type)
0532   QStringList scalarList;
0533 
0534   Dirfile dirfile(getDirectory(filename).toLatin1(), GD_RDONLY);
0535   if (dirfile.Error() == GD_E_OK) {
0536 
0537     scalarList.append("FRAMES");
0538     const char **xl = dirfile.FieldListByType(ConstEntryType);
0539     for (int i = 0; xl[i]!=NULL; i++) {
0540       scalarList.append(QString::fromUtf8(xl[i]));
0541     }
0542   }
0543 
0544   if (complete) {
0545     *complete = true;
0546   }
0547 
0548   if (typeSuggestion) {
0549     *typeSuggestion = dirfileTypeString;
0550   }
0551 
0552   return scalarList;
0553 }
0554 
0555 QStringList DirFilePlugin::stringList(QSettings *cfg,
0556                                       const QString& filename,
0557                                       const QString& type,
0558                                       QString *typeSuggestion,
0559                                       bool *complete) const {
0560   Q_UNUSED(cfg);
0561   Q_UNUSED(type)
0562   QStringList stringList;
0563 
0564   Dirfile dirfile(getDirectory(filename).toLatin1(), GD_RDONLY);
0565 
0566   if (dirfile.Error() == GD_E_OK) {
0567 
0568     stringList.append("FILE");
0569     const char **tl = dirfile.FieldListByType(StringEntryType);
0570     for (int i = 0; tl[i]!=NULL; i++) {
0571       stringList.append(QString::fromUtf8(tl[i]));
0572     }
0573   }
0574 
0575   if (complete) {
0576     *complete = true;
0577   }
0578 
0579   if (typeSuggestion) {
0580     *typeSuggestion = dirfileTypeString;
0581   }
0582 
0583   return stringList;
0584 }
0585 
0586 QStringList DirFilePlugin::fieldList(QSettings *cfg,
0587                                             const QString& filename,
0588                                             const QString& type,
0589                                             QString *typeSuggestion,
0590                                             bool *complete) const {
0591   Q_UNUSED(cfg);
0592   Q_UNUSED(type)
0593 
0594   QStringList fieldList;
0595 
0596   Dirfile dirfile(getDirectory(filename).toLatin1(), GD_RDONLY);
0597 
0598   if (dirfile.Error() == GD_E_OK) {
0599 
0600     const char **vl = dirfile.VectorList();
0601     for (int i = 0; vl[i]!=NULL; i++) {
0602       fieldList.append(QString::fromUtf8(vl[i]));
0603     }
0604   }
0605 
0606   if (complete) {
0607     *complete = true;
0608   }
0609 
0610   if (typeSuggestion) {
0611     *typeSuggestion = dirfileTypeString;
0612   }
0613 
0614   return fieldList;
0615 }
0616 
0617 
0618 QString DirFilePlugin::getDirectory(QString filepath) {
0619   QFileInfo info(filepath);
0620   QString properDirPath = info.path();
0621   if (info.fileName() == "format") {
0622     //do nothing... allows for format file to be selected.
0623   } else if (info.isDir()) {
0624     //do nothing... a directory was selected.
0625     properDirPath = filepath;
0626   } else {
0627     QFile file(filepath);
0628     if (file.open(QFile::ReadOnly)) {
0629       QTextStream stream(&file);
0630       QString directoryName = stream.readLine(1000);
0631       properDirPath += '/';
0632       properDirPath += directoryName;
0633     }
0634   }
0635   return properDirPath;
0636 }
0637 
0638 
0639 int DirFilePlugin::understands(QSettings *cfg, const QString& filename) const {
0640   Q_UNUSED(cfg);
0641 
0642   Dirfile dirfile(getDirectory(filename).toLatin1(), GD_RDONLY);
0643 
0644   if (dirfile.Error() == GD_E_OK) {
0645     return 98;
0646   }
0647   return 0;
0648 }
0649 
0650 
0651 
0652 bool DirFilePlugin::supportsTime(QSettings *cfg, const QString& filename) const {
0653   //FIXME
0654   Q_UNUSED(cfg)
0655   Q_UNUSED(filename)
0656   return true;
0657 }
0658 
0659 
0660 QStringList DirFilePlugin::provides() const {
0661   QStringList rc;
0662   rc += dirfileTypeString;
0663   return rc;
0664 }
0665 
0666 
0667 Kst::DataSourceConfigWidget *DirFilePlugin::configWidget(QSettings *cfg, const QString& filename) const {
0668 
0669   Q_UNUSED(cfg)
0670   Q_UNUSED(filename)
0671   return 0;;
0672 
0673 }
0674 
0675 #ifndef QT5
0676 Q_EXPORT_PLUGIN2(kstdata_dirfile, DirFilePlugin)
0677 #endif
0678 
0679 // vim: ts=2 sw=2 et