Ejemplo n.º 1
0
bool FileFormat::openStreams(const QString fileName,
                             OstProto::StreamConfigList &streams, QString &error)
{
    QFile file(fileName);
    QByteArray buf;
    int size, contentOffset, contentSize;
    quint32 calcCksum;
    OstProto::FileMagic magic;
    OstProto::FileMeta meta;
    OstProto::FileContent content;
    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
    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())
        goto _missing_streams;

    postParseFixup(meta.data(), content);

    streams.CopyFrom(content.matter().streams());

    return true;

_missing_streams:
    error = QString(tr("%1 does not contain any streams")).arg(fileName);
    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:
    qDebug("%s", error.toAscii().constData());
    return false;
}