Refactored native streams file format to share code with native session file format. Added skeletal code for session/ossn file format

This commit is contained in:
Srivats P 2016-03-28 21:23:10 +05:30
parent 5b46bdd8fc
commit c98104f078
9 changed files with 848 additions and 418 deletions

View File

@ -19,160 +19,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "fileformat.h" #include "fileformat.h"
#include "crc32c.h"
#include <QApplication>
#include <QFile>
#include <QVariant>
#include <string>
const std::string FileFormat::kFileMagicValue = "\xa7\xb7OSTINATO";
FileFormat fileFormat; FileFormat fileFormat;
const int kBaseHex = 16;
FileFormat::FileFormat() FileFormat::FileFormat()
: AbstractFileFormat(), NativeFileFormat()
{ {
/* // Do Nothing!
* We don't have any "real" work to do here in the constructor.
* What we do is run some "assert" tests so that these get caught
* at init itself instead of while saving/restoring when a user
* might lose some data!
*/
OstProto::FileMagic magic;
OstProto::FileChecksum cksum;
magic.set_value(kFileMagicValue);
cksum.set_value(quint32(0));
// TODO: convert Q_ASSERT to something that will run in RELEASE mode also
Q_ASSERT(magic.IsInitialized());
Q_ASSERT(cksum.IsInitialized());
Q_ASSERT(magic.ByteSize() == kFileMagicSize);
Q_ASSERT(cksum.ByteSize() == kFileChecksumSize);
}
FileFormat::~FileFormat()
{
} }
bool FileFormat::openStreams(const QString fileName, bool FileFormat::openStreams(const QString fileName,
OstProto::StreamConfigList &streams, QString &error) OstProto::StreamConfigList &streams, QString &error)
{ {
QFile file(fileName);
QByteArray buf;
int size, contentOffset, contentSize;
quint32 calcCksum;
OstProto::FileMagic magic;
OstProto::FileMeta meta; OstProto::FileMeta meta;
OstProto::FileContent content; OstProto::FileContent content;
OstProto::FileChecksum cksum, zeroCksum; bool ret = NativeFileFormat::open(fileName, meta, content, error);
if (!file.open(QIODevice::ReadOnly))
goto _open_fail;
if (file.size() < kFileMagicSize)
goto _magic_missing;
if (file.size() < kFileMinSize)
goto _checksum_missing;
buf.resize(file.size());
size = file.read(buf.data(), buf.size());
if (size < 0)
goto _read_fail;
Q_ASSERT(file.atEnd());
file.close();
qDebug("%s: file.size() = %lld", __FUNCTION__, file.size());
qDebug("%s: size = %d", __FUNCTION__, size);
//qDebug("Read %d bytes", buf.size());
//qDebug("%s", QString(buf.toHex()).toAscii().constData());
// Parse and verify magic
if (!magic.ParseFromArray(
(void*)(buf.constData() + kFileMagicOffset),
kFileMagicSize))
{
goto _magic_parse_fail;
}
if (magic.value() != kFileMagicValue)
goto _magic_match_fail;
// Parse and verify checksum
if (!cksum.ParseFromArray(
(void*)(buf.constData() + size - kFileChecksumSize),
kFileChecksumSize))
{
goto _cksum_parse_fail;
}
zeroCksum.set_value(0);
if (!zeroCksum.SerializeToArray(
(void*) (buf.data() + size - kFileChecksumSize),
kFileChecksumSize))
{
goto _zero_cksum_serialize_fail;
}
calcCksum = checksumCrc32C((quint8*) buf.constData(), size); if (!ret)
goto _fail;
qDebug("checksum \nExpected:%x Actual:%x",
calcCksum, cksum.value());
if (cksum.value() != calcCksum)
goto _cksum_verify_fail;
// Parse the metadata first before we parse the full contents
if (!meta.ParseFromArray(
(void*)(buf.constData() + kFileMetaDataOffset),
size - kFileMetaDataOffset))
{
goto _metadata_parse_fail;
}
qDebug("%s: File MetaData (INFORMATION) - \n%s", __FUNCTION__,
QString().fromStdString(meta.DebugString()).toAscii().constData());
// MetaData Validation(s)
if (meta.data().file_type() != OstProto::kStreamsFileType)
goto _unexpected_file_type;
if (meta.data().format_version_major() != kFileFormatVersionMajor)
goto _incompatible_file_version;
if (meta.data().format_version_minor() > kFileFormatVersionMinor)
goto _incompatible_file_version;
if (meta.data().format_version_minor() < kFileFormatVersionMinor)
{
// TODO: need to modify 'buf' such that we can parse successfully
// assuming the native minor version
}
if (meta.data().format_version_revision() > kFileFormatVersionRevision)
{
error = QString(tr("%1 was created using a newer version of Ostinato."
" New features/protocols will not be available.")).arg(fileName);
}
Q_ASSERT(meta.data().format_version_major() == kFileFormatVersionMajor);
// ByteSize() does not include the Tag/Key, so we add 2 for that
contentOffset = kFileMetaDataOffset + meta.data().ByteSize() + 2;
contentSize = size - contentOffset - kFileChecksumSize;
// Parse full contents
if (!content.ParseFromArray(
(void*)(buf.constData() + contentOffset),
contentSize))
{
goto _content_parse_fail;
}
if (!content.matter().has_streams()) if (!content.matter().has_streams())
goto _missing_streams; goto _missing_streams;
@ -186,75 +49,6 @@ bool FileFormat::openStreams(const QString fileName,
_missing_streams: _missing_streams:
error = QString(tr("%1 does not contain any streams")).arg(fileName); error = QString(tr("%1 does not contain any streams")).arg(fileName);
goto _fail; goto _fail;
_content_parse_fail:
error = QString(tr("Failed parsing %1 contents")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
content.matter().InitializationErrorString())
.toAscii().constData());
qDebug("Debug: %s", QString().fromStdString(
content.matter().DebugString()).toAscii().constData());
goto _fail;
_incompatible_file_version:
error = QString(tr("%1 is in an incompatible format version - %2.%3.%4"
" (Native version is %5.%6.%7)"))
.arg(fileName)
.arg(meta.data().format_version_major())
.arg(meta.data().format_version_minor())
.arg(meta.data().format_version_revision())
.arg(kFileFormatVersionMajor)
.arg(kFileFormatVersionMinor)
.arg(kFileFormatVersionRevision);
goto _fail;
_unexpected_file_type:
error = QString(tr("%1 is not a streams file")).arg(fileName);
goto _fail;
_metadata_parse_fail:
error = QString(tr("Failed parsing %1 meta data")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
meta.data().InitializationErrorString())
.toAscii().constData());
goto _fail;
_cksum_verify_fail:
error = QString(tr("%1 checksum validation failed!\nExpected:%2 Actual:%3"))
.arg(fileName)
.arg(calcCksum, 0, kBaseHex)
.arg(cksum.value(), 0, kBaseHex);
goto _fail;
_zero_cksum_serialize_fail:
error = QString(tr("Internal Error: Zero Checksum Serialize failed!\n"
"Error: %1\nDebug: %2"))
.arg(QString().fromStdString(
cksum.InitializationErrorString()))
.arg(QString().fromStdString(cksum.DebugString()));
goto _fail;
_cksum_parse_fail:
error = QString(tr("Failed parsing %1 checksum")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
cksum.InitializationErrorString())
.toAscii().constData());
goto _fail;
_magic_match_fail:
error = QString(tr("%1 is not an Ostinato file")).arg(fileName);
goto _fail;
_magic_parse_fail:
error = QString(tr("%1 does not look like an Ostinato file")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
magic.InitializationErrorString())
.toAscii().constData());
goto _fail;
_read_fail:
error = QString(tr("Error reading from %1")).arg(fileName);
goto _fail;
_checksum_missing:
error = QString(tr("%1 is too small (missing checksum)")).arg(fileName);
goto _fail;
_magic_missing:
error = QString(tr("%1 is too small (missing magic value)"))
.arg(fileName);
goto _fail;
_open_fail:
error = QString(tr("Error opening %1")).arg(fileName);
goto _fail;
_fail: _fail:
qDebug("%s", error.toAscii().constData()); qDebug("%s", error.toAscii().constData());
return false; return false;
@ -263,25 +57,7 @@ _fail:
bool FileFormat::saveStreams(const OstProto::StreamConfigList streams, bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
const QString fileName, QString &error) const QString fileName, QString &error)
{ {
OstProto::FileMagic magic;
OstProto::FileMeta meta;
OstProto::FileContent content; OstProto::FileContent content;
OstProto::FileChecksum cksum;
QFile file(fileName);
int metaSize, contentSize;
int contentOffset, cksumOffset;
QByteArray buf;
quint32 calcCksum;
magic.set_value(kFileMagicValue);
Q_ASSERT(magic.IsInitialized());
cksum.set_value(0);
Q_ASSERT(cksum.IsInitialized());
initFileMetaData(*(meta.mutable_data()));
meta.mutable_data()->set_file_type(OstProto::kStreamsFileType);
Q_ASSERT(meta.IsInitialized());
if (!streams.IsInitialized()) if (!streams.IsInitialized())
goto _stream_not_init; goto _stream_not_init;
@ -289,104 +65,9 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
content.mutable_matter()->mutable_streams()->CopyFrom(streams); content.mutable_matter()->mutable_streams()->CopyFrom(streams);
Q_ASSERT(content.IsInitialized()); Q_ASSERT(content.IsInitialized());
metaSize = meta.ByteSize(); return NativeFileFormat::save(OstProto::kStreamsFileType, content,
contentSize = content.ByteSize(); fileName, error);
contentOffset = kFileMetaDataOffset + metaSize;
cksumOffset = contentOffset + contentSize;
Q_ASSERT(magic.ByteSize() == kFileMagicSize);
Q_ASSERT(cksum.ByteSize() == kFileChecksumSize);
buf.resize(kFileMagicSize + metaSize + contentSize + kFileChecksumSize);
// Serialize everything
if (!magic.SerializeToArray((void*) (buf.data() + kFileMagicOffset),
kFileMagicSize))
{
goto _magic_serialize_fail;
}
if (!meta.SerializeToArray((void*) (buf.data() + kFileMetaDataOffset),
metaSize))
{
goto _meta_serialize_fail;
}
if (!content.SerializeToArray((void*) (buf.data() + contentOffset),
contentSize))
{
goto _content_serialize_fail;
}
if (!cksum.SerializeToArray((void*) (buf.data() + cksumOffset),
kFileChecksumSize))
{
goto _zero_cksum_serialize_fail;
}
emit status("Calculating checksum...");
// Calculate and write checksum
calcCksum = checksumCrc32C((quint8*)buf.constData(), buf.size());
cksum.set_value(calcCksum);
if (!cksum.SerializeToArray(
(void*) (buf.data() + cksumOffset),
kFileChecksumSize))
{
goto _cksum_serialize_fail;
}
qDebug("Writing %d bytes", buf.size());
//qDebug("%s", QString(buf.toHex()).toAscii().constData());
emit status("Writing to disk...");
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
goto _open_fail;
if (file.write(buf) < 0)
goto _write_fail;
file.close();
return true;
_write_fail:
error = QString(tr("Error writing to %1")).arg(fileName);
goto _fail;
_open_fail:
error = QString(tr("Error opening %1 (Error Code = %2)"))
.arg(fileName)
.arg(file.error());
goto _fail;
_cksum_serialize_fail:
error = QString(tr("Internal Error: Checksum Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
cksum.InitializationErrorString()))
.arg(QString().fromStdString(cksum.DebugString()));
goto _fail;
_zero_cksum_serialize_fail:
error = QString(tr("Internal Eror: Zero Checksum Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
cksum.InitializationErrorString()))
.arg(QString().fromStdString(cksum.DebugString()));
goto _fail;
_content_serialize_fail:
error = QString(tr("Internal Error: Content Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
content.InitializationErrorString()))
.arg(QString().fromStdString(content.DebugString()));
goto _fail;
_meta_serialize_fail:
error = QString(tr("Internal Error: Meta Data Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
meta.InitializationErrorString()))
.arg(QString().fromStdString(meta.DebugString()));
goto _fail;
_magic_serialize_fail:
error = QString(tr("Internal Error: Magic Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
magic.InitializationErrorString()))
.arg(QString().fromStdString(magic.DebugString()));
goto _fail;
_stream_not_init: _stream_not_init:
error = QString(tr("Internal Error: Streams not initialized\n%1\n%2")) error = QString(tr("Internal Error: Streams not initialized\n%1\n%2"))
.arg(QString().fromStdString( .arg(QString().fromStdString(
@ -400,26 +81,7 @@ _fail:
bool FileFormat::isMyFileFormat(const QString fileName) bool FileFormat::isMyFileFormat(const QString fileName)
{ {
bool ret = false; return isNativeFileFormat(fileName, OstProto::kStreamsFileType);
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) bool FileFormat::isMyFileType(const QString fileType)
@ -430,54 +92,3 @@ bool FileFormat::isMyFileType(const QString fileType)
return false; return false;
} }
void FileFormat::initFileMetaData(OstProto::FileMetaData &metaData)
{
// Fill in the "native" file format version
metaData.set_format_version_major(kFileFormatVersionMajor);
metaData.set_format_version_minor(kFileFormatVersionMinor);
metaData.set_format_version_revision(kFileFormatVersionRevision);
metaData.set_generator_name(
qApp->applicationName().toUtf8().constData());
metaData.set_generator_version(
qApp->property("version").toString().toUtf8().constData());
metaData.set_generator_revision(
qApp->property("revision").toString().toUtf8().constData());
}
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/*! Fixup content to what is expected in the native version */
void FileFormat::postParseFixup(OstProto::FileMetaData metaData,
OstProto::FileContent &content)
{
Q_ASSERT(metaData.format_version_major() == kFileFormatVersionMajor);
// Do fixups from oldest to newest versions
switch (metaData.format_version_minor())
{
case 1:
{
int n = content.matter().streams().stream_size();
for (int i = 0; i < n; i++)
{
OstProto::StreamControl *sctl =
content.mutable_matter()->mutable_streams()->mutable_stream(i)->mutable_control();
sctl->set_packets_per_sec(sctl->obsolete_packets_per_sec());
sctl->set_bursts_per_sec(sctl->obsolete_bursts_per_sec());
}
// fall-through to next higher version until native version
}
case kFileFormatVersionMinor: // native version
break;
case 0:
default:
qWarning("%s: minor version %u unhandled", __FUNCTION__,
metaData.format_version_minor());
Q_ASSERT_X(false, "postParseFixup", "unhandled minor version");
}
}
#pragma GCC diagnostic warning "-Wdeprecated-declarations"

View File

@ -20,14 +20,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#define _FILE_FORMAT_H #define _FILE_FORMAT_H
#include "abstractfileformat.h" #include "abstractfileformat.h"
#include "nativefileformat.h"
#include "fileformat.pb.h" #include "fileformat.pb.h"
class FileFormat : public AbstractFileFormat class FileFormat : public AbstractFileFormat, public NativeFileFormat
{ {
public: public:
FileFormat(); FileFormat();
~FileFormat();
virtual bool openStreams(const QString fileName, virtual bool openStreams(const QString fileName,
OstProto::StreamConfigList &streams, QString &error); OstProto::StreamConfigList &streams, QString &error);
@ -36,25 +36,6 @@ public:
bool isMyFileFormat(const QString fileName); bool isMyFileFormat(const QString fileName);
bool isMyFileType(const QString fileType); bool isMyFileType(const QString fileType);
private:
void initFileMetaData(OstProto::FileMetaData &metaData);
void postParseFixup(OstProto::FileMetaData metaData,
OstProto::FileContent &content);
static const int kFileMagicSize = 12;
static const int kFileChecksumSize = 5;
static const int kFileMinSize = kFileMagicSize + kFileChecksumSize;
static const int kFileMagicOffset = 0;
static const int kFileMetaDataOffset = kFileMagicSize;
static const std::string kFileMagicValue;
// Native file format version
static const uint kFileFormatVersionMajor = 0;
static const uint kFileFormatVersionMinor = 2;
static const uint kFileFormatVersionRevision = 4;
}; };
extern FileFormat fileFormat; extern FileFormat fileFormat;

470
common/nativefileformat.cpp Normal file
View File

@ -0,0 +1,470 @@
/*
Copyright (C) 2010, 2016 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 <http://www.gnu.org/licenses/>
*/
#include "nativefileformat.h"
#include "crc32c.h"
#include <QApplication>
#include <QFile>
#include <QVariant>
#define tr(str) QObject::tr(str)
const std::string NativeFileFormat::kFileMagicValue = "\xa7\xb7OSTINATO";
static const int kBaseHex = 16;
NativeFileFormat::NativeFileFormat()
{
/*
* We don't have any "real" work to do here in the constructor.
* What we do is run some "assert" tests so that these get caught
* at init itself instead of while saving/restoring when a user
* might lose some data!
*/
OstProto::FileMagic magic;
OstProto::FileChecksum cksum;
magic.set_value(kFileMagicValue);
cksum.set_value(quint32(0));
// TODO: convert Q_ASSERT to something that will run in RELEASE mode also
Q_ASSERT(magic.IsInitialized());
Q_ASSERT(cksum.IsInitialized());
Q_ASSERT(magic.ByteSize() == kFileMagicSize);
Q_ASSERT(cksum.ByteSize() == kFileChecksumSize);
}
bool NativeFileFormat::open(
const QString fileName,
OstProto::FileMeta &meta,
OstProto::FileContent &content,
QString &error)
{
QFile file(fileName);
QByteArray buf;
int size, contentOffset, contentSize;
quint32 calcCksum;
OstProto::FileMagic magic;
OstProto::FileChecksum cksum, zeroCksum;
if (!file.open(QIODevice::ReadOnly))
goto _open_fail;
if (file.size() < kFileMagicSize)
goto _magic_missing;
if (file.size() < kFileMinSize)
goto _checksum_missing;
buf.resize(file.size());
size = file.read(buf.data(), buf.size());
if (size < 0)
goto _read_fail;
Q_ASSERT(file.atEnd());
file.close();
qDebug("%s: file.size() = %lld", __FUNCTION__, file.size());
qDebug("%s: size = %d", __FUNCTION__, size);
//qDebug("Read %d bytes", buf.size());
//qDebug("%s", QString(buf.toHex()).toAscii().constData());
// Parse and verify magic
if (!magic.ParseFromArray(
(void*)(buf.constData() + kFileMagicOffset),
kFileMagicSize))
{
goto _magic_parse_fail;
}
if (magic.value() != kFileMagicValue)
goto _magic_match_fail;
// Parse and verify checksum
if (!cksum.ParseFromArray(
(void*)(buf.constData() + size - kFileChecksumSize),
kFileChecksumSize))
{
goto _cksum_parse_fail;
}
zeroCksum.set_value(0);
if (!zeroCksum.SerializeToArray(
(void*) (buf.data() + size - kFileChecksumSize),
kFileChecksumSize))
{
goto _zero_cksum_serialize_fail;
}
calcCksum = checksumCrc32C((quint8*) buf.constData(), size);
qDebug("checksum \nExpected:%x Actual:%x",
calcCksum, cksum.value());
if (cksum.value() != calcCksum)
goto _cksum_verify_fail;
// Parse the metadata first before we parse the full contents
// FIXME: metadata size is not known beforehand, so we end up
// parsing till EOF
if (!meta.ParseFromArray(
(void*)(buf.constData() + kFileMetaDataOffset),
size - kFileMetaDataOffset))
{
goto _metadata_parse_fail;
}
qDebug("%s: File MetaData (INFORMATION) - \n%s", __FUNCTION__,
QString().fromStdString(meta.DebugString()).toAscii().constData());
qDebug("%s: END MetaData", __FUNCTION__);
// MetaData Validation(s)
if (meta.data().file_type() != OstProto::kStreamsFileType)
goto _unexpected_file_type;
if (meta.data().format_version_major() != kFileFormatVersionMajor)
goto _incompatible_file_version;
if (meta.data().format_version_minor() > kFileFormatVersionMinor)
goto _incompatible_file_version;
if (meta.data().format_version_minor() < kFileFormatVersionMinor)
{
// TODO: need to modify 'buf' such that we can parse successfully
// assuming the native minor version
}
if (meta.data().format_version_revision() > kFileFormatVersionRevision)
{
error = QString(tr("%1 was created using a newer version of Ostinato."
" New features/protocols will not be available.")).arg(fileName);
}
Q_ASSERT(meta.data().format_version_major() == kFileFormatVersionMajor);
// ByteSize() does not include the Tag/Key, so we add 2 for that
contentOffset = kFileMetaDataOffset + meta.data().ByteSize() + 2;
contentSize = size - contentOffset - kFileChecksumSize;
qDebug("%s: content offset/size = %d/%d", __FUNCTION__,
contentOffset, contentSize);
// Parse full contents
if (!content.ParseFromArray(
(void*)(buf.constData() + contentOffset),
contentSize))
{
goto _content_parse_fail;
}
return true;
_content_parse_fail:
error = QString(tr("Failed parsing %1 contents")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
content.InitializationErrorString())
.toAscii().constData());
qDebug("Debug: %s", QString().fromStdString(
content.DebugString()).toAscii().constData());
goto _fail;
_incompatible_file_version:
error = QString(tr("%1 is in an incompatible format version - %2.%3.%4"
" (Native version is %5.%6.%7)"))
.arg(fileName)
.arg(meta.data().format_version_major())
.arg(meta.data().format_version_minor())
.arg(meta.data().format_version_revision())
.arg(kFileFormatVersionMajor)
.arg(kFileFormatVersionMinor)
.arg(kFileFormatVersionRevision);
goto _fail;
_unexpected_file_type:
error = QString(tr("%1 is not a streams file")).arg(fileName);
goto _fail;
_metadata_parse_fail:
error = QString(tr("Failed parsing %1 meta data")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
meta.data().InitializationErrorString())
.toAscii().constData());
goto _fail;
_cksum_verify_fail:
error = QString(tr("%1 checksum validation failed!\nExpected:%2 Actual:%3"))
.arg(fileName)
.arg(calcCksum, 0, kBaseHex)
.arg(cksum.value(), 0, kBaseHex);
goto _fail;
_zero_cksum_serialize_fail:
error = QString(tr("Internal Error: Zero Checksum Serialize failed!\n"
"Error: %1\nDebug: %2"))
.arg(QString().fromStdString(
cksum.InitializationErrorString()))
.arg(QString().fromStdString(cksum.DebugString()));
goto _fail;
_cksum_parse_fail:
error = QString(tr("Failed parsing %1 checksum")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
cksum.InitializationErrorString())
.toAscii().constData());
goto _fail;
_magic_match_fail:
error = QString(tr("%1 is not an Ostinato file")).arg(fileName);
goto _fail;
_magic_parse_fail:
error = QString(tr("%1 does not look like an Ostinato file")).arg(fileName);
qDebug("Error: %s", QString().fromStdString(
magic.InitializationErrorString())
.toAscii().constData());
goto _fail;
_read_fail:
error = QString(tr("Error reading from %1")).arg(fileName);
goto _fail;
_checksum_missing:
error = QString(tr("%1 is too small (missing checksum)")).arg(fileName);
goto _fail;
_magic_missing:
error = QString(tr("%1 is too small (missing magic value)"))
.arg(fileName);
goto _fail;
_open_fail:
error = QString(tr("Error opening %1")).arg(fileName);
goto _fail;
_fail:
qDebug("%s", error.toAscii().constData());
return false;
}
bool NativeFileFormat::save(
OstProto::FileType fileType,
const OstProto::FileContent &content,
const QString fileName,
QString &error)
{
OstProto::FileMagic magic;
OstProto::FileMeta meta;
OstProto::FileChecksum cksum;
QFile file(fileName);
int metaSize, contentSize;
int contentOffset, cksumOffset;
QByteArray buf;
quint32 calcCksum;
magic.set_value(kFileMagicValue);
Q_ASSERT(magic.IsInitialized());
cksum.set_value(0);
Q_ASSERT(cksum.IsInitialized());
initFileMetaData(*(meta.mutable_data()));
meta.mutable_data()->set_file_type(fileType);
Q_ASSERT(meta.IsInitialized());
if (!content.IsInitialized())
goto _content_not_init;
Q_ASSERT(content.IsInitialized());
metaSize = meta.ByteSize();
contentSize = content.ByteSize();
contentOffset = kFileMetaDataOffset + metaSize;
cksumOffset = contentOffset + contentSize;
Q_ASSERT(magic.ByteSize() == kFileMagicSize);
Q_ASSERT(cksum.ByteSize() == kFileChecksumSize);
buf.resize(kFileMagicSize + metaSize + contentSize + kFileChecksumSize);
// Serialize everything
if (!magic.SerializeToArray((void*) (buf.data() + kFileMagicOffset),
kFileMagicSize))
{
goto _magic_serialize_fail;
}
if (!meta.SerializeToArray((void*) (buf.data() + kFileMetaDataOffset),
metaSize))
{
goto _meta_serialize_fail;
}
if (!content.SerializeToArray((void*) (buf.data() + contentOffset),
contentSize))
{
goto _content_serialize_fail;
}
if (!cksum.SerializeToArray((void*) (buf.data() + cksumOffset),
kFileChecksumSize))
{
goto _zero_cksum_serialize_fail;
}
// TODO: emit status("Calculating checksum...");
// Calculate and write checksum
calcCksum = checksumCrc32C((quint8*)buf.constData(), buf.size());
cksum.set_value(calcCksum);
if (!cksum.SerializeToArray(
(void*) (buf.data() + cksumOffset),
kFileChecksumSize))
{
goto _cksum_serialize_fail;
}
qDebug("Writing %d bytes", buf.size());
//qDebug("%s", QString(buf.toHex()).toAscii().constData());
// TODO: emit status("Writing to disk...");
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
goto _open_fail;
if (file.write(buf) < 0)
goto _write_fail;
file.close();
return true;
_write_fail:
error = QString(tr("Error writing to %1")).arg(fileName);
goto _fail;
_open_fail:
error = QString(tr("Error opening %1 (Error Code = %2)"))
.arg(fileName)
.arg(file.error());
goto _fail;
_cksum_serialize_fail:
error = QString(tr("Internal Error: Checksum Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
cksum.InitializationErrorString()))
.arg(QString().fromStdString(cksum.DebugString()));
goto _fail;
_zero_cksum_serialize_fail:
error = QString(tr("Internal Eror: Zero Checksum Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
cksum.InitializationErrorString()))
.arg(QString().fromStdString(cksum.DebugString()));
goto _fail;
_content_serialize_fail:
error = QString(tr("Internal Error: Content Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
content.InitializationErrorString()))
.arg(QString().fromStdString(content.DebugString()));
goto _fail;
_meta_serialize_fail:
error = QString(tr("Internal Error: Meta Data Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
meta.InitializationErrorString()))
.arg(QString().fromStdString(meta.DebugString()));
goto _fail;
_magic_serialize_fail:
error = QString(tr("Internal Error: Magic Serialize failed\n%1\n%2"))
.arg(QString().fromStdString(
magic.InitializationErrorString()))
.arg(QString().fromStdString(magic.DebugString()));
goto _fail;
_content_not_init:
error = QString(tr("Internal Error: Content not initialized\n%1\n%2"))
.arg(QString().fromStdString(
content.InitializationErrorString()))
.arg(QString().fromStdString(content.DebugString()));
goto _fail;
_fail:
qDebug("%s", error.toAscii().constData());
return false;
}
bool NativeFileFormat::isNativeFileFormat(
const QString fileName,
OstProto::FileType fileType)
{
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;
// TODO: check fileType
_close_exit:
file.close();
_exit:
return ret;
}
void NativeFileFormat::initFileMetaData(OstProto::FileMetaData &metaData)
{
// Fill in the "native" file format version
metaData.set_format_version_major(kFileFormatVersionMajor);
metaData.set_format_version_minor(kFileFormatVersionMinor);
metaData.set_format_version_revision(kFileFormatVersionRevision);
metaData.set_generator_name(
qApp->applicationName().toUtf8().constData());
metaData.set_generator_version(
qApp->property("version").toString().toUtf8().constData());
metaData.set_generator_revision(
qApp->property("revision").toString().toUtf8().constData());
}
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/*! Fixup content to what is expected in the native version */
void NativeFileFormat::postParseFixup(OstProto::FileMetaData metaData,
OstProto::FileContent &content)
{
Q_ASSERT(metaData.format_version_major() == kFileFormatVersionMajor);
// Do fixups from oldest to newest versions
switch (metaData.format_version_minor())
{
case 1:
{
int n = content.matter().streams().stream_size();
for (int i = 0; i < n; i++)
{
OstProto::StreamControl *sctl =
content.mutable_matter()->mutable_streams()->mutable_stream(i)->mutable_control();
sctl->set_packets_per_sec(sctl->obsolete_packets_per_sec());
sctl->set_bursts_per_sec(sctl->obsolete_bursts_per_sec());
}
// fall-through to next higher version until native version
}
case kFileFormatVersionMinor: // native version
break;
case 0:
default:
qWarning("%s: minor version %u unhandled", __FUNCTION__,
metaData.format_version_minor());
Q_ASSERT_X(false, "postParseFixup", "unhandled minor version");
}
}
#pragma GCC diagnostic warning "-Wdeprecated-declarations"

75
common/nativefileformat.h Normal file
View File

@ -0,0 +1,75 @@
/*
Copyright (C) 2010, 2016 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 <http://www.gnu.org/licenses/>
*/
#ifndef _NATIVE_FILE_FORMAT_H
#define _NATIVE_FILE_FORMAT_H
/*
* This file contains helper functions for the native file format
* defined in fileformat.proto
*
* The actual file format classes - (Ostm)FileFormat and OssnFileFormat
* use multiple inheritance from the abstract interface class and this
* helper class
*
* The primary reason for the existence of this class is to have a common
* code for dealing with native file formats
*/
#include "fileformat.pb.h"
#include <QString>
class NativeFileFormat
{
public:
NativeFileFormat();
bool open(const QString fileName,
OstProto::FileMeta &meta,
OstProto::FileContent &content,
QString &error);
bool save(OstProto::FileType fileType,
const OstProto::FileContent &content,
const QString fileName,
QString &error);
bool isNativeFileFormat(const QString fileName,
OstProto::FileType fileType);
void postParseFixup(OstProto::FileMetaData metaData,
OstProto::FileContent &content);
private:
void initFileMetaData(OstProto::FileMetaData &metaData);
static const int kFileMagicSize = 12;
static const int kFileChecksumSize = 5;
static const int kFileMinSize = kFileMagicSize + kFileChecksumSize;
static const int kFileMagicOffset = 0;
static const int kFileMetaDataOffset = kFileMagicSize;
static const std::string kFileMagicValue;
// Native file format version
static const uint kFileFormatVersionMajor = 0;
static const uint kFileFormatVersionMinor = 2;
static const uint kFileFormatVersionRevision = 4;
};
#endif

46
common/ossnfileformat.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
Copyright (C) 2016 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 <http://www.gnu.org/licenses/>
*/
#include "ossnfileformat.h"
bool OssnFileFormat::open(const QString fileName,
OstProto::SessionContent &session, QString &error)
{
// TODO
return false;
}
bool OssnFileFormat::save(const OstProto::SessionContent &session,
const QString fileName, QString &error)
{
// TODO
return false;
}
bool OssnFileFormat::isMyFileFormat(const QString fileName)
{
// TODO
return true;
}
bool OssnFileFormat::isMyFileType(const QString fileType)
{
// TODO
return true;
}

40
common/ossnfileformat.h Normal file
View File

@ -0,0 +1,40 @@
/*
Copyright (C) 2016 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 <http://www.gnu.org/licenses/>
*/
#ifndef _OSSN_FILE_FORMAT_H
#define _OSSN_FILE_FORMAT_H
#include "sessionfileformat.h"
class OssnFileFormat : public SessionFileFormat
{
public:
virtual bool open(const QString fileName,
OstProto::SessionContent &session, QString &error);
virtual bool save(const OstProto::SessionContent &session,
const QString fileName, QString &error);
virtual bool isMyFileFormat(const QString fileName);
virtual bool isMyFileType(const QString fileType);
};
extern OssnFileFormat ossnFileFormat;
#endif

View File

@ -39,12 +39,15 @@ HEADERS = \
fileformat.h \ fileformat.h \
ipv4addressdelegate.h \ ipv4addressdelegate.h \
ipv6addressdelegate.h \ ipv6addressdelegate.h \
nativefileformat.h \
ossnfileformat.h \
pcapfileformat.h \ pcapfileformat.h \
pdmlfileformat.h \ pdmlfileformat.h \
pythonfileformat.h \ pythonfileformat.h \
pdmlprotocol.h \ pdmlprotocol.h \
pdmlprotocols.h \ pdmlprotocols.h \
pdmlreader.h \ pdmlreader.h \
sessionfileformat.h \
spinboxdelegate.h spinboxdelegate.h
HEADERS += \ HEADERS += \
@ -82,12 +85,15 @@ SOURCES += \
ostprotolib.cpp \ ostprotolib.cpp \
abstractfileformat.cpp \ abstractfileformat.cpp \
fileformat.cpp \ fileformat.cpp \
nativefileformat.cpp \
ossnfileformat.cpp \
pcapfileformat.cpp \ pcapfileformat.cpp \
pdmlfileformat.cpp \ pdmlfileformat.cpp \
pythonfileformat.cpp \ pythonfileformat.cpp \
pdmlprotocol.cpp \ pdmlprotocol.cpp \
pdmlprotocols.cpp \ pdmlprotocols.cpp \
pdmlreader.cpp \ pdmlreader.cpp \
sessionfileformat.cpp \
spinboxdelegate.cpp spinboxdelegate.cpp
SOURCES += \ SOURCES += \

View File

@ -0,0 +1,111 @@
/*
Copyright (C) 2016 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 <http://www.gnu.org/licenses/>
*/
#include "sessionfileformat.h"
#include "ossnfileformat.h"
#include <QStringList>
SessionFileFormat::SessionFileFormat()
{
stop_ = false;
}
SessionFileFormat::~SessionFileFormat()
{
}
QDialog* SessionFileFormat::openOptionsDialog()
{
return NULL;
}
QDialog* SessionFileFormat::saveOptionsDialog()
{
return NULL;
}
QStringList SessionFileFormat::supportedFileTypes()
{
return QStringList()
<< "Ostinato Session (*.ossn)";
}
void SessionFileFormat::openOffline(const QString fileName,
OstProto::SessionContent &session, QString &error)
{
fileName_ = fileName;
openSession_ = &session;
error_ = &error;
op_ = kOpen;
stop_ = false;
start();
}
void SessionFileFormat::saveOffline(
const OstProto::SessionContent &session,
const QString fileName, QString &error)
{
saveSession_ = &session;
fileName_ = fileName;
error_ = &error;
op_ = kSave;
stop_ = false;
start();
}
bool SessionFileFormat::result()
{
return result_;
}
SessionFileFormat* SessionFileFormat::fileFormatFromFile(
const QString fileName)
{
if (ossnFileFormat.isMyFileFormat(fileName))
return &ossnFileFormat;
return NULL;
}
SessionFileFormat* SessionFileFormat::fileFormatFromType(
const QString fileType)
{
if (ossnFileFormat.isMyFileType(fileType))
return &ossnFileFormat;
return NULL;
}
void SessionFileFormat::cancel()
{
stop_ = true;
}
void SessionFileFormat::run()
{
if (op_ == kOpen)
result_ = open(fileName_, *openSession_, *error_);
else if (op_ == kSave)
result_ = save(*saveSession_, fileName_, *error_);
}

View File

@ -0,0 +1,90 @@
/*
Copyright (C) 2016 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 <http://www.gnu.org/licenses/>
*/
#ifndef _SESSION_FILE_FORMAT_H
#define _SESSION_FILE_FORMAT_H
#include "fileformat.pb.h"
#include "protocol.pb.h"
#include <QThread>
#include <QString>
class QDialog;
class SessionFileFormat : public QThread
{
Q_OBJECT
public:
SessionFileFormat();
virtual ~SessionFileFormat();
virtual bool open(const QString fileName,
OstProto::SessionContent &session, QString &error) = 0;
virtual bool save(const OstProto::SessionContent &session,
const QString fileName, QString &error) = 0;
virtual QDialog* openOptionsDialog();
virtual QDialog* saveOptionsDialog();
void openOffline(const QString fileName,
OstProto::SessionContent &session, QString &error);
void saveOffline(const OstProto::SessionContent &session,
const QString fileName, QString &error);
bool result();
static QStringList supportedFileTypes();
static SessionFileFormat* fileFormatFromFile(const QString fileName);
static SessionFileFormat* fileFormatFromType(const QString fileType);
virtual bool isMyFileFormat(const QString fileName) = 0;
virtual bool isMyFileType(const QString fileType) = 0;
signals:
void status(QString text);
void target(int value);
void progress(int value);
public slots:
void cancel();
protected:
void run();
bool stop_;
private:
enum kOp {
kOpen,
kSave
};
QString fileName_;
OstProto::SessionContent *openSession_;
const OstProto::SessionContent *saveSession_;
QString *error_;
kOp op_;
bool result_;
};
#endif