Custom IO Device/de

From Qt Wiki
Jump to navigation Jump to search
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.

German | English


Wie man ein benutzerdefiniertes I/O-Gerät schreibt

Dies ist eine Portierung des Artikels Qt Quarterly 12 about writing a custom QIODevice

Benutzung:

Der folgende Code-Schnipsel zeigt, wie man das benutzerdefinierte I/O-Gerät benutzen würde, um Daten zu verschlüsseln und das Ergebnis in einer Datei zu speichern:

 QFile file("output.dat");
 CryptDevice cryptDevice(&file)
 QTextStream out(&cryptDevice);
 cryptDevice.open(QIODevice::WriteOnly);
 out << "Hello World";

Zur möglichen Verwendung siehe auch unseren Beispiel-Code in git qtdevnet-wiki-mvc/qtdevnet-custom-iodevice .


Verschlüsselung

 QByteArray dataArray;

QBuffer bufferUsedLikeAFile(&dataArray);
 CryptDevice deviceFilter(&bufferUsedLikeAFile);
 deviceFilter.open(QIODevice::WriteOnly);
 QTextStream stream(&deviceFilter);
 QString szText = rawText->toPlainText();
 stream << szText;


Entschlüsselung

 QBuffer bufferUsedLikeAFile(&dataArray);
 CryptDevice deviceFilter(&bufferUsedLikeAFile);
 deviceFilter.open(QIODevice::ReadOnly);
 QTextStream stream(&deviceFilter);
 QString szText = stream.readAll();
 decryptedText->setPlainText(szText);

Das Beispiel-Bild aus dem Testprogramm:

Test app

Das benutzerdefinierte I/O-Gerät

Das Schreiben eines benutzerdefinierten I/O-Gerätes in Qt 4 umfasst das Erstellen einer von QIODevice abgeleiteten Klasse und das Reimplementieren einiger virtueller Funktionen.

Im Vergleich zu Qt 3 gibt dabei einen großen Unterschied: Man muss nur noch 2 Funktionen neu schreiben:

  • qint64 QIODevice::readData ( char * data, qint64 maxSize )
  • qint64 QIODevice::writeData ( const char * data, qint64 maxSize )

Unsere CryptDevice-Klasse wird ein sequenzielles I/O-Gerät. Ob es synchron oder asynchron arbeitet, hängt vom darunter liegenden QIODevice ab.

Quelltext

Die Klassendefinition sieht folgendermaßen aus:

class CryptDevice : public QIODevice
{
 Q_OBJECT
public:
 CryptDevice(QIODevice* deviceToUse, QObject* parent = 0);
 bool open(OpenMode mode);
 void close();
 bool isSequential() const;
protected:
 qint64 readData(char* data, qint64 maxSize);
 qint64 writeData(const char* data, qint64 maxSize);
private:
 QIODevice* underlyingDevice;
 Q_DISABLE_COPY(CryptDevice)
};

Die Definition des Constructors ist ganz einfach:

CryptDevice::CryptDevice(QIODevice* deviceToUse, QObject* parent) :
 QIODevice(parent),
 underlyingDevice(deviceToUse)
{
}

Weil wir ein sequenzielles Gerät haben wollen, reimplementieren wir isSequential:

bool CryptDevice::isSequential() const
{
 return true;
}

in

open()

öffnen wir das darunter liegende Gerät, falls es nicht schon geöffnet ist, und setzetn den Gerätezustand auf mode.

bool CryptDevice::open(OpenMode mode)
{
 bool underlyingOk;
 if (underlyingDevice->isOpen())
 underlyingOk = (underlyingDevice->openMode() != mode);
 else
 underlyingOk = underlyingDevice->open(mode);

if (underlyingOk)
 {
 setOpenMode(mode);
 return true;
 }
 return false;
}

Das Schließen ist trivial.

void CryptDevice::close()
{
 underlyingDevice->close();
 setOpenMode(NotOpen);
}

Um einen Block zu lesen, rufen wir von dem darunter liegenden Gerät

read()

auf. Am Ende verknüpfen wir alle gelesenen Bytes XOR mit der magischen Konstante 0x5E.

qint64 CryptDevice::readData(char* data, qint64 maxSize)
{
 qint64 deviceRead = underlyingDevice->read(data, maxSize);
 if (deviceRead == 1)
 return -1;
 for (qint64 i = 0; i < deviceRead; +''i)
 data[i] = data[i] ^ 0x5E;

 return deviceRead;
}

Um einen Block zu schreiben, erzeugen wir einen temporären Puffer mit unseren ge-XOR-ten Daten. Eine effizientere Implementierung würde einen 4096-Byte-Puffer auf dem Stack nutzen und

write()

mehrfach aufrufen, wenn die Größe der Daten die des Puffers übersteigt.

qint64 CryptDevice::writeData(const char* data, qint64 maxSize)
{
 QByteArray buffer((int)maxSize, 0);
 for (int i = 0; i < (int)maxSize;''+i)
 buffer[i] = data[i] ^ 0x5E;
 return underlyingDevice->write(buffer.data(), maxSize);
}