示例#1
0
void HciManager::handleLeMetaEvent(const quint8 *data)
{
    // Spec v4.2, Vol 2, part E, 7.7.65ff
    switch (*data) {
    case 0x1: {
        const quint16 handle = bt_get_le16(data + 2);
        emit connectionComplete(handle);
        break;
    }
    case 0x3: {
        // TODO: From little endian!
        struct ConnectionUpdateData {
            quint8 status;
            quint16 handle;
            quint16 interval;
            quint16 latency;
            quint16 timeout;
        } __attribute((packed));
        const auto * const updateData
                = reinterpret_cast<const ConnectionUpdateData *>(data + 1);
        if (updateData->status == 0) {
            QLowEnergyConnectionParameters params;
            const double interval = qFromLittleEndian(updateData->interval) * 1.25;
            params.setIntervalRange(interval, interval);
            params.setLatency(qFromLittleEndian(updateData->latency));
            params.setSupervisionTimeout(qFromLittleEndian(updateData->timeout) * 10);
            emit connectionUpdate(qFromLittleEndian(updateData->handle), params);
        }
        break;
    }
    default:
        break;
    }
}
int Value::usedStorage(const Base *b) const
{
    int s = 0;
    switch (type) {
    case QJsonValue::Double:
        if (latinOrIntValue)
            break;
        s = sizeof(double);
        break;
    case QJsonValue::String: {
        char *d = data(b);
        if (latinOrIntValue)
            s = sizeof(ushort) + qFromLittleEndian(*(ushort *)d);
        else
            s = sizeof(int) + sizeof(ushort) * qFromLittleEndian(*(int *)d);
        break;
    }
    case QJsonValue::Array:
    case QJsonValue::Object:
        s = base(b)->size;
        break;
    case QJsonValue::Null:
    case QJsonValue::Bool:
    default:
        break;
    }
    return alignedSize(s);
}
示例#3
0
void PacketDecodeNode::processByteArray( QByteArray A )
{
	if( A.size() < sizeof( PktHdr ) )
	{
		return;
	}

	PktHdr		PacketHeader;

	memcpy( &PacketHeader, A.constData(), sizeof( PacketHeader ) );

	PacketHeader.mLength = qFromLittleEndian( PacketHeader.mLength );

	if( PacketHeader.mLength != A.size() )
	{
		return;
	}

	PacketHeader.mCRC = qFromLittleEndian( PacketHeader.mCRC );

	memset( A.data() + offsetof( PktHdr, mCRC ), 0, sizeof( quint32 ) );

	quint32		CRC = CRC32::crc32( A );

	if( CRC != PacketHeader.mCRC )
	{
		return;
	}

	if( PacketHeader.mLength > sizeof( PacketHeader ) )
	{
		mValOutputData->variantAppend( A.mid( sizeof( PacketHeader ) ) );
	}
}
示例#4
0
void HciManager::handleHciAclPacket(const quint8 *data, int size)
{
    if (size < int(sizeof(AclData))) {
        qCWarning(QT_BT_BLUEZ) << "Unexpected HCI ACL packet size";
        return;
    }

    quint16 rawAclData[sizeof(AclData) / sizeof(quint16)];
    rawAclData[0] = bt_get_le16(data);
    rawAclData[1] = bt_get_le16(data + sizeof(quint16));
    const AclData *aclData = reinterpret_cast<AclData *>(rawAclData);
    data += sizeof *aclData;
    size -= sizeof *aclData;

    // Consider only directed, complete messages.
    if ((aclData->pbFlag != 0 && aclData->pbFlag != 2) || aclData->bcFlag != 0)
        return;

    if (size < aclData->dataLen) {
        qCWarning(QT_BT_BLUEZ) << "HCI ACL packet data size" << size
                               << "is smaller than specified size" << aclData->dataLen;
        return;
    }

//    qCDebug(QT_BT_BLUEZ) << "handle:" << aclData->handle << "PB:" << aclData->pbFlag
//                         << "BC:" << aclData->bcFlag << "data len:" << aclData->dataLen;

    if (size < int(sizeof(L2CapHeader))) {
        qCWarning(QT_BT_BLUEZ) << "Unexpected HCI ACL packet size";
        return;
    }
    L2CapHeader l2CapHeader = *reinterpret_cast<const L2CapHeader*>(data);
    l2CapHeader.channelId = qFromLittleEndian(l2CapHeader.channelId);
    l2CapHeader.length = qFromLittleEndian(l2CapHeader.length);
    data += sizeof l2CapHeader;
    size -= sizeof l2CapHeader;
    if (size < l2CapHeader.length) {
        qCWarning(QT_BT_BLUEZ) << "L2Cap payload size" << size << "is smaller than specified size"
                               << l2CapHeader.length;
        return;
    }
//    qCDebug(QT_BT_BLUEZ) << "l2cap channel id:" << l2CapHeader.channelId
//                         << "payload length:" << l2CapHeader.length;
    if (l2CapHeader.channelId != SECURITY_CHANNEL_ID)
        return;
    if (*data != 0xa) // "Signing Information". Spec v4.2, Vol 3, Part H, 3.6.6
        return;
    if (size != 17) {
        qCWarning(QT_BT_BLUEZ) << "Unexpected key size" << size << "in Signing Information packet";
        return;
    }
    quint128 csrk;
    memcpy(&csrk, data + 1, sizeof csrk);
    const bool isRemoteKey = aclData->pbFlag == 2;
    emit signatureResolvingKeyReceived(aclData->handle, isRemoteKey, csrk);
}
示例#5
0
文件: VstPlugin.cpp 项目: karmux/lmms
	MachineType machineType()
	{
		int32_t peOffset = qFromLittleEndian(* reinterpret_cast<int32_t*>(m_map + 0x3C));
		uchar* peSignature = m_map + peOffset;
		if (memcmp(peSignature, "PE\0\0", 4)) {
			throw std::runtime_error("Invalid PE file");
		}
		uchar * coffHeader = peSignature + 4;
		uint16_t machineType = qFromLittleEndian(* reinterpret_cast<uint16_t*>(coffHeader));
		return static_cast<MachineType>(machineType);
	}
示例#6
0
quint32 getUnsignedDWord(const void *src)
{
    quint32 result = 0;
    memcpy(reinterpret_cast<void *>(&result), src, 4);
    result = qFromLittleEndian(result);
    return result;
}
示例#7
0
qint64 getSignedQWord(const void *src)
{
    qint64 result = 0;
    memcpy(reinterpret_cast<void *>(&result), src, 8);
    result = qFromLittleEndian(result);
    return result;
}
示例#8
0
qint64 StateImport::loadCTM5(State *state, QFile& file, struct CTMHeader5* v5header)
{
    if (v5header->flags & 03)
    {
        state->setErrorMessage(QObject::tr("Error: CTM is not expanded"));
        qDebug() << "CTM is not expanded. Cannot load it";
        return -1;
    }

    int num_chars = qFromLittleEndian(v5header->num_chars);
    int toRead = std::min(num_chars * 8, State::CHAR_BUFFER_SIZE);

    // clean previous memory in case not all the chars are loaded
    state->resetCharsetBuffer();

    auto total = file.read((char*)state->getCharsetBuffer(), toRead);

    for (int i=0; i<4; i++)
        state->setColorForPen(i, v5header->colors[i]);

    state->setMulticolorMode(v5header->flags & 0b00000100);

    State::TileProperties tp;
    tp.interleaved = 1;
    // some files reports size == 0. Bug in CTMv5?
    tp.size.setWidth(qMax((int)v5header->tile_width,1));
    tp.size.setHeight(qMax((int)v5header->tile_height,1));
    state->setTileProperties(tp);

    return total;
}
示例#9
0
	CacheEntry MemcachedCache::value(const QString& key) const
	{
		QReadLocker lock(&m_lock);

		const QByteArray rawKey(fullKey(key));

		char* rawData;
		size_t rawDataLength;
		uint32_t flags;
		memcached_return rt;

		rawData = memcached_get(
			m_memcached,
			rawKey.constData(),
			rawKey.length(),
			&rawDataLength,
			&flags,
			&rt
		);

		if(rt != MEMCACHED_SUCCESS && rt != MEMCACHED_NOTFOUND)
		{
			qFatal("Memcached error: %s", memcached_strerror(m_memcached, rt));
		}

		Q_ASSERT(rawDataLength >= sizeof(quint64) || !rawData);
		if(rawDataLength < sizeof(quint64) || !rawData)
		{
			return CacheEntry();
		}
		
		const quint64 timeStamp = qFromLittleEndian(*reinterpret_cast<quint64*>(rawData));
		const QByteArray data(rawData + sizeof(quint64), rawDataLength - sizeof(quint64));
		return CacheEntry(QDateTime::fromTime_t(timeStamp), data);
	}
示例#10
0
int Sample::toInt() const
{
    if (signal->sampleSize() == 1)
    {
        if (signal->getFormat().sampleType() == QAudioFormat::SignedInt)
        {
            return constSampleData[0];
        }
        else
        {
            return static_cast<unsigned char>(sampleData[0]);
        }
    }
    else if (signal->sampleSize() == 2)
    {
        if (signal->getFormat().sampleType() == QAudioFormat::SignedInt)
        {
            const short* val = reinterpret_cast<const short*>(constSampleData);
            if (signal->getFormat().byteOrder() == QAudioFormat::LittleEndian)
            {
                return qFromLittleEndian(*val);
            }
            else
            {
                return qFromBigEndian(*val);
            }
        }
        else
        {
            const unsigned short* val = reinterpret_cast<const unsigned short*>(sampleData);
            if (signal->getFormat().byteOrder() == QAudioFormat::LittleEndian)
            {
                return qFromLittleEndian(*val);
            }
            else
            {
                return qFromBigEndian(*val);
            }
        }
    }
    else
    {
        throw Signal::SampleSizeUnset();
    }
}
quint32 PeerToPeerPacket::requiredLen(const QByteArray &p_data)
{
    // Return the minimum length (to have the actual length)
    if(p_data.length() < 4)
        return 4;

    // Return the length as the header states (first two bytes)
    return qFromLittleEndian(*(reinterpret_cast<const quint32*>(p_data.constData())));
}
示例#12
0
qint32 readSignedDWord(QIODevice &device)
{
    qint32 result = 0;
    if (device.read(reinterpret_cast<char *> (&result),
            Q_INT64_C(4)) != Q_INT64_C(4))
    {
        throw std::runtime_error("Unable to read file");
    }
    result = qFromLittleEndian(result);
    return result;
}
void Transfer::onReadyRead()
{
    // Add all of the new data to the buffer
    mBuffer.append(mSocket->readAll());

    // Process as many packets as can be read from the buffer
    forever {

        // If the transfer is finished, ignore any packets being received
        if (mProtocolState == ProtocolState::Finished) {
            break;
        }

        // If the size of the packet is not yet known attempt to read it
        if (!mBufferSize) {

            // See if there is enough data in the buffer to read the size
            if (static_cast<size_t>(mBuffer.size()) >= sizeof(mBufferSize)) {

                // memcpy must be used in order to avoid alignment issues
                // Also, the integer uses little endian byte order
                // so convert it to the host format if necessary
                memcpy(&mBufferSize, mBuffer.constData(), sizeof(mBufferSize));
                mBufferSize = qFromLittleEndian(mBufferSize);
                mBuffer.remove(0, sizeof(mBufferSize));

                // A packet size of zero is an error
                if (!mBufferSize) {
                    writeErrorPacket(tr("Empty packet received"));
                    break;
                }

            } else {
                break;
            }
        }

        // If the buffer contains enough data to read the packet, then do so
        if (mBuffer.size() >= mBufferSize) {
            processPacket();
        } else {
            break;
        }
    }
}
示例#14
0
qint64 StateImport::loadVChar64(State *state, QFile& file)
{
    struct VChar64Header header;
    auto size = file.size();
    if ((std::size_t)size<sizeof(header))
    {
        state->setErrorMessage(QObject::tr("Error: Invalid VChar file"));
        qDebug() << "Error. File size too small to be VChar64 (" << size << ").";
        return -1;
    }

    size = file.read((char*)&header, sizeof(header));
    if ((std::size_t)size<sizeof(header))
        return -1;

    // check header
    if (header.id[0] != 'V' || header.id[1] != 'C' || header.id[2] != 'h' || header.id[3] != 'a' || header.id[4] != 'r')
    {
        state->setErrorMessage(QObject::tr("Error: Invalid VChar file"));
        qDebug() << "Not a valid VChar64 file";
        return -1;
    }


    int num_chars = qFromLittleEndian((int)header.num_chars);
    int toRead = std::min(num_chars * 8, State::CHAR_BUFFER_SIZE);

    // clean previous memory in case not all the chars are loaded
    state->resetCharsetBuffer();

    auto total = file.read((char*)state->getCharsetBuffer(), toRead);

    for (int i=0; i<4; i++)
        state->setColorForPen(i, header.colors[i]);

    state->setMulticolorMode(header.vic_res);
    State::TileProperties properties;
    properties.size = {header.tile_width, header.tile_height};
    properties.interleaved = header.char_interleaved;
    state->setTileProperties(properties);

    return total;
}
示例#15
0
qint64 StateImport::loadPRG(State *state, QFile& file, quint16* outAddress)
{
    auto size = file.size();
    if (size < 10) { // 2 + 8 (at least one char)
        state->setErrorMessage(QObject::tr("Error: File size too small"));
        qDebug() << "Error: File Size too small.";
        return -1;
    }

    // ignore first 2 bytes
    quint16 address;
    file.read((char*)&address, 2);

    if (outAddress) {
        *outAddress = qFromLittleEndian(address);
    }

    return StateImport::loadRaw(state, file);
}
示例#16
0
void ARControlConnection::onNavdata(const ARControlFrame &frame)
{
    Q_D(ARControlConnection);

    // TODO: Should we do this, or should we allow application to decide
    // when/if an acknowledge occurs?
    // Construct acknowledge frame, if this incoming frame requires it.
    if(frame.type == ARControlConnection::AcknowledgeData)
    {
        QByteArray payload(1, 0x00);
        QDataStream datastream(&payload, QIODevice::WriteOnly);
        datastream.setByteOrder(QDataStream::LittleEndian);
        datastream << (quint8)frame.seq;
        sendFrame(ARControlConnection::Acknowledge, ARNET_C2D_NAVDATA_ACK_ID, payload.constData(), payload.size());
    }

    // Decode command header.
    quint8  project  = static_cast<quint8>(frame.payload[0]);
    quint8  klass    = static_cast<quint8>(frame.payload[1]);
    quint16 id       = qFromLittleEndian(static_cast<quint16>(frame.payload[2]));
    const char *data = frame.payload.data() + 4;

    // Resolve command meta-type information.
    ARCommandInfo *command = d->commands->find(project, klass, id);
    if(command == NULL)
    {
        WARNING_T(QString("Unrecognised command: %1 %2 %3")
                  .arg(project)
                  .arg(klass)
                  .arg(id));
        return;
    }

    // Use command codec to decode command parameters.
    QVariantMap params = d->codec->decode(command, data);
    DEBUG_T(QString("Decoded Command %1 %2 %3").arg(command->klass->project).arg(command->klass->name).arg(command->name));

    d->controller->onCommandReceived(*command, params);
}
示例#17
0
qint64 StateImport::loadCTM4(State *state, QFile& file, struct CTMHeader4* v4header)
{
    // only expanded files are supported
    if (!v4header->expanded)
    {
        state->setErrorMessage(QObject::tr("Error: CTM is not expanded"));
        qDebug() << "CTM is not expanded. Cannot load it";
        return -1;
    }

    // only 20 bytes were read, but v4 headers has 24 bytes.
    // but the 4 remaing bytes are not important.
    char ignore[4];
    file.read(ignore, sizeof(ignore));

    int num_chars = qFromLittleEndian(v4header->num_chars);
    int toRead = std::min(num_chars * 8, State::CHAR_BUFFER_SIZE);

    // clean previous memory in case not all the chars are loaded
    state->resetCharsetBuffer();

    auto total = file.read((char*)state->getCharsetBuffer(), toRead);

    for (int i=0; i<4; i++)
        state->setColorForPen(i, v4header->colors[i]);

    state->setMulticolorMode(v4header->vic_res);

    State::TileProperties tp;
    tp.interleaved = 1;
    tp.size.setWidth(v4header->tile_width);
    tp.size.setHeight(v4header->tile_height);
    state->setTileProperties(tp);

    return total;
}
PeerToPeerPacket *PeerToPeerPacket::parseData(const QByteArray &p_data)
{
    // Return an invalid packet, if there is not even a complete header
    if(p_data.length() < XFIRE_HEADER_LEN_P2P)
        return 0;

    quint32 offset = 0;

    // Packet length
    quint32 len = requiredLen(p_data);
    offset += 4;
    
    // Return an invalid packet, if there is not enough data available
    if((len < XFIRE_HEADER_LEN_P2P) || (p_data.length() < len))
        return 0;
    
    // Packet id
    quint16 id = qFromLittleEndian(*(reinterpret_cast<const quint16*>(p_data.constData() + offset)));
    offset += 2;

    // Attribute count
    quint8 attr_count = *(reinterpret_cast<const quint8*>(p_data.constData() + offset));
    offset += 1;

    PeerToPeerPacket *ret = new PeerToPeerPacket(id);

    static const quint16 stringPackets[] =
    {
        0x3E87, 0x3E88, 0x3E89, 0x3E8A, 0x3E8B, 0x3E8C, 0x3E8D, 0x3E8E, 0x0000
    };

    bool uses_strings = false;
    int i = 0;
    
    while(stringPackets[i] != 0x0000)
    {
        if(stringPackets[i] == id)
        {
            uses_strings = true;
            break;
        }

        i++;
    }

    for(i = 0; i < attr_count; i++)
    {
        Attribute *attr = uses_strings ? Attribute::parseAttributeString(p_data, offset, len) : Attribute::parseAttributeByte(p_data, offset, len);
        // Return an invalid packet, if at least one attribute parsing failed
        if(!attr || !attr->isValid())
        {
            if(attr)
                delete attr;

            delete ret;
            return 0;
        }

        ret->m_attributes.append(attr);
    }

    // Return an invalid packet, if the size did not match the attributes
    if(offset != len)
    {
        delete ret;
        return 0;
    }

    return ret;
}
示例#19
0
void ARControlConnection::onVideoData(const ARControlFrame &frame)
{
    TRACE
    Q_D(ARControlConnection);

    quint16 frameNumber = qFromLittleEndian(*((quint16*)(frame.payload.constData())));
    quint8  frameFlags = static_cast<quint8>(frame.payload[2]);
    quint8  fragmentNumber = static_cast<quint8>(frame.payload[3]);
    quint8  fragsPerFrame = static_cast<quint8>(frame.payload[4]);

    if(frameNumber != d->frameNumber)
    {
        if(frameFlags == 0x01)
        {
            DEBUG_T(QString("Video Key Frame Header [%1] (%2 %3 %4)")
                    .arg(QString(QByteArray().append(frame.payload.constData(), 5).toHex()))
                    .arg(frameNumber)
                    .arg(fragmentNumber)
                    .arg(fragsPerFrame));
        }
        else
        {
            DEBUG_T(QString("Video Frame Header (%2 %3 %4)")
                    .arg(frameNumber)
                    .arg(fragmentNumber)
                    .arg(fragsPerFrame));
        }

        if(fragsPerFrame < 64)
        {
            d->hiAck = 0xffffffffffffffff;
            d->loAck = 0xffffffffffffffff << fragsPerFrame;
        }
        else if(fragsPerFrame < 128)
        {
            d->hiAck = 0xffffffffffffffff << (fragsPerFrame - 64);
            d->loAck = 0ll;
        }
        else
        {
            d->hiAck = 0ll;
            d->loAck = 0ll;
        }

        d->frameNumber = frameNumber;
    }

    if(fragmentNumber < 64)
    {
        d->loAck |= (1ll << fragmentNumber);
    }
    else if(fragmentNumber < 128)
    {
        d->hiAck |= (1ll << (fragmentNumber - 64));
    }

    // Construct reply.
    QByteArray payload(2 + 8 + 8, 0x00);
    QDataStream datastream(&payload, QIODevice::WriteOnly);

    if(!d->sequenceIds.contains(ARNET_C2D_VIDEO_ACK_ID))
        d->sequenceIds.insert(ARNET_C2D_VIDEO_ACK_ID, 0x00);

    datastream.setByteOrder(QDataStream::LittleEndian);
    datastream
            << (quint16)frameNumber
            << (quint64)d->hiAck
            << (quint64)d->loAck;

    sendFrame(ARControlConnection::LowLatencyData, ARNET_C2D_VIDEO_ACK_ID, payload.constData(), payload.size());
}
示例#20
0
void ARControlConnection::onReadyRead()
{
    Q_D(ARControlConnection);

    while(d->d2c->hasPendingDatagrams())
    {
        QHostAddress remoteAddr;
        quint16      remotePort;

        // If we've not received enough data, then return and wait for more.
        if(d->d2c->pendingDatagramSize() < ARNETWORK_FRAME_HEADER_SIZE) break;

        QByteArray datagram(d->d2c->pendingDatagramSize(), 0x00);
        quint32 offset = 0;

        d->d2c->readDatagram(datagram.data(), datagram.size(), &remoteAddr, &remotePort);

        while(offset < datagram.size())
        {
            ARControlFrame frame;
            frame.type = static_cast<quint8>(datagram[offset + 0]);
            frame.id = static_cast<quint8>(datagram[offset + 1]);
            frame.seq = static_cast<quint8>(datagram[offset + 2]);
            frame.size = qFromLittleEndian(*((quint32*)(datagram.constData() + offset + 3)));

            // Copy datagram data to frame if the frame size is larger than just the header.
            if(frame.size > ARNETWORK_FRAME_HEADER_SIZE)
            {
                const char *data = datagram.constData();
                frame.payload.insert(0, data + offset + ARNETWORK_FRAME_HEADER_SIZE, frame.size - ARNETWORK_FRAME_HEADER_SIZE);
            }

            // Output comms debug info (if it's not a video data frame).
            if(frame.id != ARNET_D2C_VIDEO_DATA_ID)
            {
                DEBUG_T(QString("<< %1:%2 [%3]")
                        .arg(remoteAddr.toString())
                        .arg(remotePort)
                        .arg(QString(datagram.toHex())));
            }

            // Process frame depending on buffer id.
            if(frame.id == ARNET_D2C_PING_ID)
            {
                onPing(frame);
            }
            else if(frame.id == ARNET_D2C_EVENT_ID || frame.id == ARNET_D2C_NAVDATA_ID)
            {
                onNavdata(frame);
            }
            else if(frame.id == ARNET_D2C_VIDEO_DATA_ID)
            {
                onVideoData(frame);
            }
            else
            {
                WARNING_T(QString("Unhandled frame id: %1").arg(frame.id));
            }

            // Increment datagram offset to continue processing next frame.
            offset += frame.size;
        }
    }
}
示例#21
0
qint64 StateImport::parseVICESnapshot(QFile& file, quint8* buffer64k)
{
    struct VICESnapshotHeader header;
    struct VICESnapshoptModule module;
    struct VICESnapshoptC64Mem c64mem;

    static const char VICE_MAGIC[] = "VICE Snapshot File\032";
    static const char VICE_C64MEM[] = "C64MEM";

    auto state = State::getInstance();

    if (!file.isOpen())
        file.open(QIODevice::ReadOnly);

    auto size = file.size();
    if (size < (qint64)sizeof(VICESnapshotHeader))
    {
        state->setErrorMessage(QObject::tr("Error: VICE file too small"));
        return -1;
    }

    file.seek(0);
    size = file.read((char*)&header, sizeof(header));
    if (size != sizeof(header))
    {
        state->setErrorMessage(QObject::tr("Error: VICE header too small"));
        return -1;
    }

    if (memcmp(header.id, VICE_MAGIC, sizeof(header.id)) != 0)
    {
        state->setErrorMessage(QObject::tr("Error: Invalid VICE header Id"));
        return -1;
    }

    int offset = file.pos();
    bool found = false;

    while (1) {
        size = file.read((char*)&module, sizeof(module));
        if (size != sizeof(module))
            break;

        /* Found?  */
        if (memcmp(module.moduleName, VICE_C64MEM, sizeof(VICE_C64MEM)) == 0 &&
                module.major == 0)
        {
            found = true;
            break;
        }
        offset += qFromLittleEndian(module.lenght);
        if (!file.seek(offset))
            break;
    }

    if (found)
    {
        size = file.read((char*)&c64mem, sizeof(c64mem));
        if (size != sizeof(c64mem))
        {
            state->setErrorMessage(QObject::tr("Error: Invalid VICE C64MEM segment"));
            return -1;
        }

        memcpy(buffer64k, c64mem.ram, sizeof(c64mem.ram));
    }
    else
    {
        state->setErrorMessage(QObject::tr("Error: VICE C64MEM segment not found"));
        return -1;
    }

    return 0;
}
示例#22
0
文件: QueryHit.cpp 项目: geekt/quazaa
CQueryHit* CQueryHit::ReadPacket(G2Packet *pPacket, QSharedPointer<QueryHitInfo> pHitInfo)
{
	if( !pPacket->m_bCompound )
        return 0;

	pPacket->m_nPosition = 0; // reset packet position

    bool bHaveHits = false;
    bool bFirstHit = true;

    CQueryHit* pThisHit = new CQueryHit();

	try
	{
		char szType[9], szTypeX[9];
		quint32 nLength = 0, nLengthX = 0, nNext = 0, nNextX = 0;
		bool bCompound = false;

		while( pPacket->ReadPacket(&szType[0], nLength, &bCompound) )
		{
			nNext = pPacket->m_nPosition + nLength;

			if( strcmp("H", szType) == 0 && bCompound )
			{
				CQueryHit* pHit = (bFirstHit ? pThisHit : new CQueryHit());

				if( !bFirstHit )
				{
					CQueryHit* pPrevHit = pThisHit;
					while( pPrevHit->m_pNext != 0 )
					{
						pPrevHit = pPrevHit->m_pNext;
					}
					pPrevHit->m_pNext = pHit;
				}

				bool bHaveSize = false;
				QByteArray baTemp;
				bool bHaveDN = false;
				bool bHaveURN = false;

				while( pPacket->m_nPosition < nNext && pPacket->ReadPacket(&szTypeX[0], nLengthX))
				{
					nNextX = pPacket->m_nPosition + nLengthX;

					if( strcmp("URN", szTypeX) == 0 )
					{
						QString sURN;
						char hashBuff[256];
						sURN = pPacket->ReadString();

						if( nLengthX >= 44u && sURN.compare("bp") == 0 )
						{
							pPacket->Read(&hashBuff[0], CSHA1::ByteCount());
							if( pHit->m_oSha1.FromRawData(&hashBuff[0], CSHA1::ByteCount()) )
							{
								bHaveURN = true;
							}
							else
							{
								pHit->m_oSha1.Clear();
							}
						}
						else if( nLengthX >= CSHA1::ByteCount() + 5u && sURN.compare("sha1") == 0 )
						{
							pPacket->Read(&hashBuff[0], CSHA1::ByteCount());
							if( pHit->m_oSha1.FromRawData(&hashBuff[0], CSHA1::ByteCount()) )
							{
								bHaveURN = true;
							}
							else
							{
								pHit->m_oSha1.Clear();
							}
						}


					}
					else if( strcmp("URL", szTypeX) == 0 && nLengthX )
					{
						// if url empty - try uri-res resolver or a node do not have this object
						// bez sensu...
						pHit->m_sURL = pPacket->ReadString();
					}
					else if( strcmp("DN", szTypeX) == 0 )
					{
						if( bHaveSize )
						{
							pHit->m_sDescriptiveName = pPacket->ReadString(nLengthX);
						}
						else if( nLengthX > 4 )
						{
							baTemp.resize(4);
							pPacket->Read(baTemp.data(), 4);
							pHit->m_sDescriptiveName = pPacket->ReadString(nLengthX - 4);
						}

						bHaveDN = true;
					}
					else if( strcmp("MD", szTypeX) == 0 )
					{
						pHit->m_sMetadata = pPacket->ReadString();
					}
					else if( strcmp("SZ", szTypeX) == 0 && nLengthX >= 4 )
					{
						if( nLengthX >= 8 )
						{
							if( !baTemp.isEmpty() )
							{
								pHit->m_sDescriptiveName.prepend(baTemp);
							}
							pHit->m_nObjectSize = pPacket->ReadIntLE<quint64>();
							bHaveSize = true;
						}
						else if( nLengthX >= 4 )
						{
							if( !baTemp.isEmpty() )
							{
								pHit->m_sDescriptiveName.prepend(baTemp);
							}
							pHit->m_nObjectSize = pPacket->ReadIntLE<quint32>();
							bHaveSize = true;
						}
					}
					else if( strcmp("CSC", szTypeX) == 0 && nLengthX >= 2 )
					{
						pHit->m_nCachedSources = pPacket->ReadIntLE<quint16>();
					}
					else if( strcmp("PART", szTypeX) == 0 && nLengthX >= 4 )
					{
						pHit->m_bIsPartial = true;
						pHit->m_nPartialBytesAvailable = pPacket->ReadIntLE<quint32>();
					}
					pPacket->m_nPosition = nNextX;
				}

				if( !bHaveSize && baTemp.size() == 4 )
				{
					pHit->m_nObjectSize = qFromLittleEndian(*(quint32*)baTemp.constData());
				}
				else
				{
					pHit->m_sDescriptiveName.prepend(baTemp);
				}

				if( bHaveURN && bHaveDN )
				{
					bFirstHit = false;
					bHaveHits = true;
				}
				else
				{
					if( !bFirstHit )
					{
						// może teraz się nie wywali...
						// można by było to lepiej zrobić...
						for( CQueryHit* pTest = pThisHit; pTest != 0; pTest = pTest->m_pNext )
						{
							if( pTest->m_pNext == pHit )
							{
								pTest->m_pNext = 0;
								break;
							}
						}
						pHit->Delete();
					}
				}
			}

			pPacket->m_nPosition = nNext;
		}
	}
	catch(...) // packet incomplete, packet error, parser takes care of stream end
	{
		qDebug() << "EXCEPTION IN QUERY HIT PARSING!";
		if( pThisHit )
		{
			pThisHit->Delete();
		}
		//throw;
		return 0;
	}

	// we already know query hit informations, so don't reparse them
	if( !bHaveHits )
	{
		pThisHit->Delete();
		return 0;
	}

    CQueryHit* pHit = pThisHit;

    while( pHit != 0 )
    {
        pHit->m_pHitInfo = pHitInfo;

        pHit = pHit->m_pNext;
    }


    // TODO: sprawdzic poprawnosc hita... (Validate hit)

    pHit = pThisHit;

    while( pHit != 0 )
    {
        pHit->ResolveURLs();
        pHit = pHit->m_pNext;
    }

    return pThisHit;
}