Ejemplo n.º 1
0
MessageRecord Reader::readNext()
{
	MessageRecord msg;

	if(!readNextToBuffer(_msgbuf))
		return msg;

	protocol::Message *message;
	switch(_formatversion) {
		// see protocol changelog in doc/protocol.md
		case version32(11, 3):
		case version32(11, 2):
			message = compat::deserializeV11((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;
		default:
			message = protocol::Message::deserialize((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;
	}

	if(message) {
		msg.status = MessageRecord::OK;
		msg.message = message;
	} else {
		msg.status = MessageRecord::INVALID;
		msg.error.len = protocol::Message::sniffLength(_msgbuf.constData());
		msg.error.type = protocol::MessageType(_msgbuf.at(2));
	}

	return msg;
}
Ejemplo n.º 2
0
bool Writer::writeHibernationHeader(const HibernationHeader &header)
{
	Q_ASSERT(_file->isOpen());

	// Format identification (note the 'H' ending)
	const char *MAGIC = "DPRECH";
	_file->write(MAGIC, 7);

	// Protocol version
	// Major version is always the same as the server version, but minor version
	// is taken from the session
	uchar version[4];
	qToBigEndian(version32(DRAWPILE_PROTO_MAJOR_VERSION, header.minorVersion), version);
	_file->write((const char*)version, 4);

	// Program version (this is always the server version)
	const char *VERSION = DRAWPILE_VERSION;
	_file->write(VERSION, qstrlen(VERSION)+1);

	// Hibernation format version
	char hver = 1;
	_file->write(&hver, 1);

	// Session title
	QByteArray title = header.title.toUtf8();
	uchar titlelen[2];
	qToBigEndian<quint16>(title.length(), titlelen);
	_file->write((const char*)titlelen, 2);
	_file->write(title);

	// Session founder name
	QByteArray founder = header.founder.toUtf8();
	Q_ASSERT(founder.length() < 256); // usernames should be limited to something way shorter than this
	uchar founderlen = qMin(founder.length(), 255);
	_file->putChar(founderlen);
	_file->write(founder);

	// Session flags
	char flags = header.flags;
	_file->write(&flags, 1);

	// Session password
	QByteArray password = header.password;
	uchar passwdlen[2];
	qToBigEndian<quint16>(password.length(), passwdlen);
	_file->write((const char*)passwdlen, 2);
	_file->write(password);

	return true;
}
Ejemplo n.º 3
0
bool Writer::writeHeader()
{
	Q_ASSERT(_file->isOpen());

	// Format identification
	const char *MAGIC = "DPRECR";
	_file->write(MAGIC, 7);

	// Protocol version
	uchar version[4];
	qToBigEndian(version32(DRAWPILE_PROTO_MAJOR_VERSION, DRAWPILE_PROTO_MINOR_VERSION), version);
	_file->write((const char*)version, 4);

	// Program version
	const char *VERSION = DRAWPILE_VERSION;
	_file->write(VERSION, qstrlen(VERSION)+1);

	return true;
}
Ejemplo n.º 4
0
Compatibility Reader::open()
{
	if(!_file->isOpen()) {
		if(!_file->open(QFile::ReadOnly)) {
			return CANNOT_READ;
		}
	}

	// Read magic bytes "DPRECR\0" or "DPRECH\0"
	char buf[7];
	if(_file->read(buf, 7) != 7)
		return CANNOT_READ;

	if(memcmp(buf, "DPRECR", 7)) {
		if(memcmp(buf, "DPRECH", 7))
			return NOT_DPREC;
		_isHibernation = true;
	}

	// Read protocol version
	if(_file->read(buf, 4) != 4)
		return NOT_DPREC;
	_formatversion = qFromBigEndian<quint32>((const uchar*)buf);

	// Read program version
	QByteArray progver;
	do {
		if(_file->read(buf, 1) != 1)
			return NOT_DPREC;
		progver.append(buf[0]);
	} while(buf[0] != '\0');
	_writerversion = QString::fromUtf8(progver);

	// If this is a hibernation file, read the rest of the header
	if(_isHibernation) {
		// We already read the protocol minor version
		_hibheader.minorVersion = minorVersion(_formatversion);

		// Check hibernation file format version
		char fmtver;
		if(!_file->getChar(&fmtver))
			return NOT_DPREC;

		// Currently there is only one format and no forward compatibility
		if((uchar)fmtver != 1)
			return INCOMPATIBLE;

		// Read session title
		if(_file->read(buf, 2) != 2)
			return NOT_DPREC;

		quint16 titleLen = qFromBigEndian<quint16>((const uchar*)buf);
		QByteArray title = _file->read(titleLen);
		if(title.length() != titleLen)
			return NOT_DPREC;

		_hibheader.title = QString::fromUtf8(title);

		// Read session founder name
		if(_file->read(buf, 1) != 1)
				return NOT_DPREC;
		quint8 founderLen = *buf;

		QByteArray founder = _file->read(founderLen);
		if(founder.length() != founderLen)
			return NOT_DPREC;

		_hibheader.founder = QString::fromUtf8(founder);

		// Read session flags
		char flags;
		if(!_file->getChar(&flags))
			return NOT_DPREC;
		_hibheader.flags = HibernationHeader::Flags((uchar)flags);

		// Read session password
		if(_file->read(buf, 2) != 2)
			return NOT_DPREC;

		quint16 passwdLen = qFromBigEndian<quint16>((const uchar*)buf);
		_hibheader.password = _file->read(passwdLen);
		if(_hibheader.password.length() != passwdLen)
			return NOT_DPREC;
	}

	_beginning = _file->pos();

	if(_isHibernation) {
		// Compatibility check is simple for hibernation files: we only need to look at the major version
		if(DRAWPILE_PROTO_MAJOR_VERSION == majorVersion(_formatversion))
			return COMPATIBLE;
		else
			return INCOMPATIBLE;

	} else {
		// Compatability check for normal recordings
		const quint32 myversion = version32(DRAWPILE_PROTO_MAJOR_VERSION, DRAWPILE_PROTO_MINOR_VERSION);

		// Best case: exact version match
		if(myversion == _formatversion)
			return COMPATIBLE;

		// A recording made with a newer (major) version may contain unsupported commands.
		if(majorVersion(myversion) < majorVersion(_formatversion))
			return UNKNOWN_COMPATIBILITY;

		// Newer minor version: expect rendering differences
		if(myversion < _formatversion)
			return MINOR_INCOMPATIBILITY;

		// Old versions known to be compatible
		switch(_formatversion) {
			case version32(11, 3): // we have compatibility code for these versions
			case version32(11, 2):
				return COMPATIBLE;
		}

		// Other versions are not supported
		return INCOMPATIBLE;
	}
}
Ejemplo n.º 5
0
Compatibility Reader::open()
{
	if(!m_file->isOpen()) {
		if(!m_file->open(QFile::ReadOnly)) {
			return CANNOT_READ;
		}
	}

	// Read magic bytes "DPREC\0"
	char buf[6];
	if(m_file->read(buf, 6) != 6)
		return CANNOT_READ;

	if(memcmp(buf, "DPREC", 6) != 0) {
		// This may be a pre 2.0 recording
		if(memcmp(buf, "DPRECR", 6)==0)
			return INCOMPATIBLE;

		return NOT_DPREC;
	}

	// Read metadata block
	if(m_file->read(buf, 2) != 2)
		return NOT_DPREC;
	const quint16 metadatalen = qFromBigEndian<quint16>((const uchar*)buf);

	QByteArray metadatabuf = m_file->read(metadatalen);
	if(metadatabuf.length() != metadatalen)
		return NOT_DPREC;

	QJsonParseError jsonError;
	QJsonDocument metadatadoc = QJsonDocument::fromJson(metadatabuf, &jsonError);

	if(jsonError.error != QJsonParseError::NoError) {
		qWarning() << jsonError.errorString();
		return NOT_DPREC;
	}

	m_metadata = metadatadoc.object();

	// Header completed!
	m_beginning = m_file->pos();

	// Check version numbers
	m_version = protocol::ProtocolVersion::fromString(m_metadata["version"].toString());

	// Best case is exact match.
	const protocol::ProtocolVersion current = protocol::ProtocolVersion::current();
	if(m_version == current)
		return COMPATIBLE;

	// Different namespace means this recording is meant for some other program
	if(m_version.ns() != current.ns())
		return NOT_DPREC;

	// A recording made with a newer (major) version may contain unsupported commands.
	if(current.major() < m_version.major())
		return UNKNOWN_COMPATIBILITY;

	// Newer minor version: expect rendering differences
	if(current.minor() < m_version.minor())
		return MINOR_INCOMPATIBILITY;

#if 0
#if DRAWPILE_PROTO_MAJOR_VERSION != 16 || DRAWPILE_PROTO_MINOR_VERSION != 1
#error Update recording compatability check!
#endif

	// Old versions known to be compatible
	switch(m_formatversion) {
	case version32(15, 5): // fully compatible (with support code)
	case version32(14, 5):
	case version32(13, 5):
	case version32(13, 4):
	case version32(12, 4):
		return COMPATIBLE;

	case version32(11, 3): // supported, but expect minor rendering differences
	case version32(11, 2):
	case version32(10, 2):
	case version32(9, 2):
	case version32(8, 1):
	case version32(7, 1):
		return MINOR_INCOMPATIBILITY;
	}
#endif

	// Other versions are not supported
	return INCOMPATIBLE;
}
Ejemplo n.º 6
0
MessageRecord Reader::readNext()
{
	MessageRecord msg;

	if(!readNextToBuffer(m_msgbuf))
		return msg;

	protocol::Message *message;
#if 0 // TODO
	if(m_formatversion != version32(DRAWPILE_PROTO_MAJOR_VERSION, DRAWPILE_PROTO_MINOR_VERSION)) {


		// see protocol changelog in doc/protocol.md
		switch(_formatversion) {
		case version32(15, 5):
			message = compat::deserializeV15_5((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(14, 5):
		case version32(13, 5):
			message = compat::deserializeV14((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(12, 4):
			message = compat::deserializeV12((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(11, 3):
		case version32(11, 2):
			message = compat::deserializeV11((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(10, 2):
		case version32(9, 2):
		case version32(8, 1):
		case version32(7, 1):
			message = compat::deserializeV10((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		default:
			message = protocol::Message::deserialize((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;
		}

		qWarning("TODO: recording compatability mode not yet implemented!");
		message = 0;
	} else {
		message = protocol::Message::deserialize((const uchar*)m_msgbuf.constData(), m_msgbuf.length(), true);
	}
#endif
	message = protocol::Message::deserialize((const uchar*)m_msgbuf.constData(), m_msgbuf.length(), true);

	if(message) {
		msg.status = MessageRecord::OK;
		msg.message = message;
	} else {
		msg.status = MessageRecord::INVALID;
		msg.error.len = protocol::Message::sniffLength(m_msgbuf.constData());
		msg.error.type = protocol::MessageType(m_msgbuf.at(2));
	}

	return msg;
}
Ejemplo n.º 7
0
MessageRecord Reader::readNext()
{
	MessageRecord msg;

	if(!readNextToBuffer(_msgbuf))
		return msg;

	protocol::Message *message;
	if(_compat && _formatversion != version32(DRAWPILE_PROTO_MAJOR_VERSION, DRAWPILE_PROTO_MINOR_VERSION)) {

		// see protocol changelog in doc/protocol.md
		switch(_formatversion) {
		case version32(15, 5):
			message = compat::deserializeV15_5((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(14, 5):
		case version32(13, 5):
			message = compat::deserializeV14((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(12, 4):
			message = compat::deserializeV12((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(11, 3):
		case version32(11, 2):
			message = compat::deserializeV11((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		case version32(10, 2):
		case version32(9, 2):
		case version32(8, 1):
		case version32(7, 1):
			message = compat::deserializeV10((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;

		default:
			message = protocol::Message::deserialize((const uchar*)_msgbuf.constData(), _msgbuf.length());
			break;
		}
	} else {
		message = protocol::Message::deserialize((const uchar*)_msgbuf.constData(), _msgbuf.length());
	}

	if(message) {
		msg.status = MessageRecord::OK;
		msg.message = message;
	} else {
		msg.status = MessageRecord::INVALID;
		msg.error.len = protocol::Message::sniffLength(_msgbuf.constData());
		msg.error.type = protocol::MessageType(_msgbuf.at(2));
	}

	return msg;
}