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:
parent
5b46bdd8fc
commit
c98104f078
@ -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"
|
|
||||||
|
|
||||||
|
@ -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
470
common/nativefileformat.cpp
Normal 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
75
common/nativefileformat.h
Normal 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
46
common/ossnfileformat.cpp
Normal 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
40
common/ossnfileformat.h
Normal 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
|
||||||
|
|
@ -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 += \
|
||||||
|
111
common/sessionfileformat.cpp
Normal file
111
common/sessionfileformat.cpp
Normal 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_);
|
||||||
|
}
|
90
common/sessionfileformat.h
Normal file
90
common/sessionfileformat.h
Normal 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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user