diff --git a/client/port.cpp b/client/port.cpp index 8d99cfd..90992ab 100644 --- a/client/port.cpp +++ b/client/port.cpp @@ -19,9 +19,7 @@ along with this program. If not, see #include "port.h" -#include "fileformat.h" -#include "pcapfileformat.h" -#include "pdmlfileformat.h" +#include "abstractfileformat.h" #include #include @@ -228,10 +226,12 @@ void Port::updateStats(OstProto::PortStats *portStats) bool Port::openStreams(QString fileName, bool append, QString &error) { OstProto::StreamConfigList streams; + AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromFile(fileName); - //if (!fileFormat.openStreams(fileName, streams, error)) - //if (!pdmlFileFormat.openStreams(fileName, streams, error)) - if (!pcapFileFormat.openStreams(fileName, streams, error)) + if (fmt == NULL) + goto _fail; + + if (!fmt->openStreams(fileName, streams, error)) goto _fail; if (!append) @@ -253,10 +253,14 @@ _fail: return false; } -bool Port::saveStreams(QString fileName, QString &error) +bool Port::saveStreams(QString fileName, QString fileType, QString &error) { + AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromType(fileType); OstProto::StreamConfigList streams; + if (fmt == NULL) + goto _fail; + streams.mutable_port_id()->set_id(0); for (int i = 0; i < mStreams.size(); i++) { @@ -264,6 +268,9 @@ bool Port::saveStreams(QString fileName, QString &error) mStreams[i]->protoDataCopyInto(*s); } - //return fileFormat.saveStreams(streams, fileName, error); - return pcapFileFormat.saveStreams(streams, fileName, error); + return fmt->saveStreams(streams, fileName, error); + +_fail: + error = QString("Unsupported File Type - %1").arg(fileType); + return false; } diff --git a/client/port.h b/client/port.h index 2fbb9a0..275ea61 100644 --- a/client/port.h +++ b/client/port.h @@ -119,7 +119,7 @@ public: void updateStats(OstProto::PortStats *portStats); bool openStreams(QString fileName, bool append, QString &error); - bool saveStreams(QString fileName, QString &error); + bool saveStreams(QString fileName, QString fileType, QString &error); signals: void portDataChanged(int portGroupId, int portId); diff --git a/client/portswindow.cpp b/client/portswindow.cpp index 58070a0..86bcf71 100644 --- a/client/portswindow.cpp +++ b/client/portswindow.cpp @@ -19,13 +19,14 @@ along with this program. If not, see #include "portswindow.h" +#include "abstractfileformat.h" +#include "streamconfigdialog.h" +#include "streamlistdelegate.h" + #include #include #include -#include "streamconfigdialog.h" -#include "streamlistdelegate.h" - PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) : QWidget(parent) { @@ -497,17 +498,44 @@ void PortsWindow::on_actionSave_Streams_triggered() QModelIndex current = tvPortList->selectionModel()->currentIndex(); QString fileName; + QStringList fileTypes = AbstractFileFormat::supportedFileTypes(); + QString fileType; QString errorStr; + QFileDialog::Options options; + + // On Mac OS with Native Dialog, getSaveFileName() ignores fileType + // which we need. +#ifdef Q_OS_MAC + options |= QFileDialog::DontUseNativeDialog; +#endif + + if (fileTypes.size()) + fileType = fileTypes.at(0); Q_ASSERT(plm->isPort(current)); - fileName = QFileDialog::getSaveFileName(this, tr("Save Streams")); +_retry: + fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"), + fileName, fileTypes.join(";;"), &fileType, options); if (fileName.isEmpty()) goto _exit; + fileType = fileType.remove(QRegExp("\\(.*\\)")).trimmed(); + if (!fileType.startsWith("Ostinato")) + { + if (QMessageBox::warning(this, tr("Ostinato"), + QString("You have chosen to save in %1 format. All stream " + "attributes may not be saved in this format.\n\n" + "It is recommended to save in native Ostinato format.\n\n" + "Continue to save in %2 format?").arg(fileType).arg(fileType), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No) != QMessageBox::Yes) + goto _retry; + } + // TODO: all or selected? - if (!plm->port(current).saveStreams(fileName, errorStr)) + if (!plm->port(current).saveStreams(fileName, fileType, errorStr)) QMessageBox::critical(this, qApp->applicationName(), errorStr); else if (!errorStr.isEmpty()) QMessageBox::warning(this, qApp->applicationName(), errorStr); diff --git a/common/abstractfileformat.cpp b/common/abstractfileformat.cpp new file mode 100644 index 0000000..cb3fa43 --- /dev/null +++ b/common/abstractfileformat.cpp @@ -0,0 +1,73 @@ +/* +Copyright (C) 2011 Srivats P. + +This file is part of "Ostinato" + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +#include "abstractfileformat.h" + +#include "fileformat.h" +#include "pcapfileformat.h" +#include "pdmlfileformat.h" + +#include + +AbstractFileFormat::AbstractFileFormat() +{ +} + +AbstractFileFormat::~AbstractFileFormat() +{ +} + +QStringList AbstractFileFormat::supportedFileTypes() +{ + return QStringList() + << "Ostinato (*)" + << "PCAP (*)" + << "PDML (*.pdml)"; +} +AbstractFileFormat* AbstractFileFormat::fileFormatFromFile( + const QString fileName) +{ + + if (fileFormat.isMyFileFormat(fileName)) + return &fileFormat; + + if (pdmlFileFormat.isMyFileFormat(fileName)) + return &pdmlFileFormat; + + if (pcapFileFormat.isMyFileFormat(fileName)) + return &pcapFileFormat; + + return NULL; +} + +AbstractFileFormat* AbstractFileFormat::fileFormatFromType( + const QString fileType) +{ + + if (fileFormat.isMyFileType(fileType)) + return &fileFormat; + + if (pdmlFileFormat.isMyFileType(fileType)) + return &pdmlFileFormat; + + if (pcapFileFormat.isMyFileType(fileType)) + return &pcapFileFormat; + + return NULL; +} diff --git a/common/abstractfileformat.h b/common/abstractfileformat.h new file mode 100644 index 0000000..7a648ee --- /dev/null +++ b/common/abstractfileformat.h @@ -0,0 +1,52 @@ +/* +Copyright (C) 2011 Srivats P. + +This file is part of "Ostinato" + +This is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +#ifndef _ABSTRACT_FILE_FORMAT_H +#define _ABSTRACT_FILE_FORMAT_H + +#include "protocol.pb.h" + +#include +#include + +class AbstractFileFormat : public QObject +{ + Q_OBJECT +public: + AbstractFileFormat(); + virtual ~AbstractFileFormat(); + + virtual bool openStreams(const QString fileName, + OstProto::StreamConfigList &streams, QString &error) = 0; + virtual bool saveStreams(const OstProto::StreamConfigList streams, + const QString fileName, QString &error) = 0; + + static AbstractFileFormat* fileFormatFromFile(const QString fileName); + static AbstractFileFormat* fileFormatFromType(const QString fileType); + + static QStringList supportedFileTypes(); + +#if 0 + bool isMyFileFormat(const QString fileName) = 0; + bool isMyFileType(const QString fileType) = 0; +#endif +}; + +#endif + diff --git a/common/fileformat.cpp b/common/fileformat.cpp index 619ab37..7ddc65b 100644 --- a/common/fileformat.cpp +++ b/common/fileformat.cpp @@ -394,6 +394,38 @@ _fail: return false; } +bool FileFormat::isMyFileFormat(const QString fileName) +{ + bool ret = false; + QFile file(fileName); + QByteArray buf; + OstProto::FileMagic magic; + + if (!file.open(QIODevice::ReadOnly)) + goto _exit; + + buf = file.peek(kFileMagicOffset + kFileMagicSize); + if (!magic.ParseFromArray((void*)(buf.constData() + kFileMagicOffset), + kFileMagicSize)) + goto _close_exit; + + if (magic.value() == kFileMagicValue) + ret = true; + +_close_exit: + file.close(); +_exit: + return ret; +} + +bool FileFormat::isMyFileType(const QString fileType) +{ + if (fileType.startsWith("Ostinato")) + return true; + else + return false; +} + void FileFormat::initFileMetaData(OstProto::FileMetaData &metaData) { // Fill in the "native" file format version diff --git a/common/fileformat.h b/common/fileformat.h index ebdc97c..0204906 100644 --- a/common/fileformat.h +++ b/common/fileformat.h @@ -19,24 +19,27 @@ along with this program. If not, see #ifndef _FILE_FORMAT_H #define _FILE_FORMAT_H +#include "abstractfileformat.h" + #include "fileformat.pb.h" -#include -#include - -class FileFormat : public QObject +class FileFormat : public AbstractFileFormat { - Q_OBJECT public: FileFormat(); ~FileFormat(); - bool openStreams(const QString fileName, + virtual bool openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error); - bool saveStreams(const OstProto::StreamConfigList streams, + virtual bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error); + bool isMyFileFormat(const QString fileName); + bool isMyFileType(const QString fileType); + private: + void initFileMetaData(OstProto::FileMetaData &metaData); + static const int kFileMagicSize = 12; static const int kFileChecksumSize = 5; static const int kFileMinSize = kFileMagicSize + kFileChecksumSize; @@ -50,8 +53,6 @@ private: static const uint kFileFormatVersionMajor = 0; static const uint kFileFormatVersionMinor = 1; static const uint kFileFormatVersionRevision = 3; - - void initFileMetaData(OstProto::FileMetaData &metaData); }; extern FileFormat fileFormat; diff --git a/common/ostproto.pro b/common/ostproto.pro index ef829da..3283090 100644 --- a/common/ostproto.pro +++ b/common/ostproto.pro @@ -57,6 +57,7 @@ PROTOS += \ HEADERS += \ abstractprotocol.h \ comboprotocol.h \ + abstractfileformat.h \ fileformat.h \ pcapfileformat.h \ pdmlfileformat.h \ @@ -98,6 +99,7 @@ HEADERS += \ SOURCES += \ abstractprotocol.cpp \ crc32c.cpp \ + abstractfileformat.cpp \ fileformat.cpp \ pcapfileformat.cpp \ pdmlfileformat.cpp \ diff --git a/common/pcapfileformat.cpp b/common/pcapfileformat.cpp index 967c565..a893565 100644 --- a/common/pcapfileformat.cpp +++ b/common/pcapfileformat.cpp @@ -25,6 +25,7 @@ along with this program. If not, see #include #include +#include #include #include #include @@ -243,7 +244,7 @@ _non_pdml: _err_unsupported_encap: error = QString(tr("%1 has non-ethernet encapsulation (%2) which is " "not supported - Sorry!")) - .arg(fileName).arg(fileHdr.network); + .arg(QFileInfo(fileName).fileName()).arg(fileHdr.network); goto _exit; #endif @@ -391,3 +392,16 @@ _exit: return isOk; } +bool PcapFileFormat::isMyFileFormat(const QString fileName) +{ + // TODO + return true; +} + +bool PcapFileFormat::isMyFileType(const QString fileType) +{ + if (fileType.startsWith("PCAP")) + return true; + else + return false; +} diff --git a/common/pcapfileformat.h b/common/pcapfileformat.h index 04a02ec..4f7ab7a 100644 --- a/common/pcapfileformat.h +++ b/common/pcapfileformat.h @@ -19,16 +19,13 @@ along with this program. If not, see #ifndef _PCAP_FILE_FORMAT_H #define _PCAP_FILE_FORMAT_H -#include "protocol.pb.h" +#include "abstractfileformat.h" #include -#include class PdmlReader; -class PcapFileFormat : public QObject +class PcapFileFormat : public AbstractFileFormat { - Q_OBJECT - friend class PdmlReader; public: @@ -40,6 +37,9 @@ public: bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error); + bool isMyFileFormat(const QString fileName); + bool isMyFileType(const QString fileType); + private: typedef struct { quint32 magicNumber; /* magic number */ diff --git a/common/pdmlfileformat.cpp b/common/pdmlfileformat.cpp index 3f86084..0c51652 100644 --- a/common/pdmlfileformat.cpp +++ b/common/pdmlfileformat.cpp @@ -92,6 +92,43 @@ _exit: bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error) { + error = "Save to PDML format is not supported"; return false; } +bool PdmlFileFormat::isMyFileFormat(const QString fileName) +{ + bool ret = false; + QFile file(fileName); + QByteArray buf; + QXmlStreamReader xml; + + if (!file.open(QIODevice::ReadOnly)) + goto _exit; + + xml.setDevice(&file); + + xml.readNext(); + if (xml.hasError() || !xml.isStartDocument()) + goto _close_exit; + + xml.readNext(); + if (!xml.hasError() && xml.isStartElement() && (xml.name() == "pdml")) + ret = true; + else + ret = false; + +_close_exit: + xml.clear(); + file.close(); +_exit: + return ret; +} + +bool PdmlFileFormat::isMyFileType(const QString fileType) +{ + if (fileType.startsWith("PDML")) + return true; + else + return false; +} diff --git a/common/pdmlfileformat.h b/common/pdmlfileformat.h index d392c6b..e05026a 100644 --- a/common/pdmlfileformat.h +++ b/common/pdmlfileformat.h @@ -19,24 +19,22 @@ along with this program. If not, see #ifndef _PDML_FILE_FORMAT_H #define _PDML_FILE_FORMAT_H -#include "protocol.pb.h" +#include "abstractfileformat.h" -#include - -class PdmlParser; - -class PdmlFileFormat : public QObject +class PdmlFileFormat : public AbstractFileFormat { - Q_OBJECT - public: PdmlFileFormat(); ~PdmlFileFormat(); - bool openStreams(const QString fileName, + virtual bool openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error); - bool saveStreams(const OstProto::StreamConfigList streams, + virtual bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error); + + bool isMyFileFormat(const QString fileName); + bool isMyFileType(const QString fileType); + }; extern PdmlFileFormat pdmlFileFormat;