Posted tagged ‘C++’

Decoding SkypeIdentityList Clipboard Data Using Qt

August 23, 2011

Whilst working on SocialClient (one of my numerous projects), I decided that I wanted to provide users with the ability to import Skype contact usernames from the clipboard (or via drag-and-drop), whilst using the Contact Builder dialogue:

Contact Builder UI

After briefly spending time searching the Web, I stumbled across an old post on the Skype fora (which happens to be the sole Google search result for “SkypeIdentityList“, at the moment), where someone requested information regarding the content of clipboard data generated by the Skype client – and provided some useful pointers for my own exploration.

With that knowledge in mind, I then obtained a copy of the Microsoft ClipBook Viewer (which doesn’t ship with Windows 7), and had a look at its “View” menu, after copying a random contact from the client’s contact list:

ClipBook Viewer

Saving the file, and then opening it with a hex editor (I used PSPad’s “Open in Hex Editor” feature – but any will suffice) revealed that the clipboard data was UTF-16-encoded text:

I initially planned to utilise QString‘s fromUtf16() method. However, further investigation lead me to believe that it was worse than useless in this case – since all that I had was the aforementioned opaque blob of data, which consisted of a header denoting the size of the following text payload, and I couldn’t find a way to convert it into the necessary format (a pointer to an unsigned, short integer; and a standard integer).

After much deliberation, and testing various potential solutions (some of which involved extracting the length data, and using it whilst iterating over the rest of the payload) that often resulted in dismal failure – involving either receiving C++ runtime assertions after attempting to access non-existent data within an array, or simply obtaining too little data to be useful, I settled upon a variant of the following solution:

QString Skype::FetchUsernameFromClipboard() {

QClipboard *clipboard = QApplication::clipboard();

if (clipboard->mimeData(QClipboard::Clipboard)
     ->data("SkypeIdentityList").length() != 0) {
QByteArray mimeData =
clipboard->mimeData(QClipboard::Clipboard)
     ->data("SkypeIdentityList");
return Skype::ParseClipboardData(mimeData);
}

else

{
return "";
}
}

QString Skype::ParseClipboardData(QByteArray aRawData) {
QByteArray workingData = aRawData;
int stringSize = aRawData.at(0);
int pos = 0;

QString round1Data, round2Data;
char tempChar;

QMap charMap;

qDebug() << "Got data:" << aRawData.toHex() <<
    "of internal length" << QString::number(stringSize);
qDebug() << "Size of array after filling is" << aRawData.size();

for (pos = 0; pos < aRawData.length() - 5; pos++) {
tempChar = workingData.at(pos + 2 + 2);
qDebug() << pos << tempChar;
round1Data = round1Data + tempChar;
}

qDebug() << "Processed data is " << round1Data.size();

for (pos = 0; pos < round1Data.size() ; pos++) {
int notNull;

if (!round1Data.at(pos).isNull()) {
notNull = pos;
qDebug() << "NOT A NULL: " << round1Data.at(pos)
   << "AT: " << pos;
charMap.insert(notNull, round1Data.at(pos));
}
}

foreach (QChar value, charMap)
round2Data = round2Data + value;

return round2Data.simplified();
}

The aforementioned implementation produces the following output, when used in conjunction with the demo method:

Got data: "070000006500630068006f00310032003300" of
    internal length "7"
Size of array after filling is 18
0 e
1
2 c
3
4 h
5
6 o
7
8 1
9
10 2
11
12 3
Processed data is 13
NOT A NULL: 'e' AT: 0
NOT A NULL: 'c' AT: 2
NOT A NULL: 'h' AT: 4
NOT A NULL: 'o' AT: 6
NOT A NULL: '1' AT: 8
NOT A NULL: '2' AT: 10
NOT A NULL: '3' AT: 12
"echo123"

Of course, code that triggers FetchUsernameFromClipboard() (or ParseClipboardData() itself) is also necessary – and the FetchUsernameFromClipboard() demo function doesn’t even exist within the SocialClient codebase; but that should give a good idea as to how I implemented this.

It probably isn’t the most efficient technique ever, either…

Still, as always, please feel free to comment and make alternative suggestions.

Advertisements

Thoughts on Process Invocation with Qt and PoCo

June 9, 2011

Since late 2010, I’ve enjoyed developing C++-based applications with the Qt framework. Overall, I find it to be intuitive, fairly well-designed, and well-documented.

However, one area of the framework that I’ve found unsatisfactory (or at least struggled with, despite my best efforts) is the QProcess class. Ideally, I’d like to be able to instantiate it once, on a per-method (or per-class) basis with the appropriate executable path and CLI arguments, and then dump its output directly into a QString for use elsewhere.

I vaguely recall successfully resolving ~90% of the problem in Stroma (although that project’s architecture is currently rather monolithic) – but I never managed to solve the rest of it (actually dumping the output of the invoked process into a QString/multi-line text box widget).

After taking a break from that project for a while, I found myself encountering a similar problem in another project; and after reading various forum/mailing list posts and pieces of documentation, sought to find alternative means of resolution.

The most promising initial candidate was Boost::Process, although it appears that development is still ongoing – therefore, it isn’t an “official” Boost component yet.

With that I mind, I decided to install and investigate Poco::Process, after seeing a mention of it on StackOverflow, last night.

Installation under Fedora was trivial (involved running “sudo yum -y install poco-devel poco-doc” from a shell), and the appropriate header files were conveniently located in /usr/include/Poco for later perusal.

That said, I was sceptical about the quality and usability of the PoCo library itself, since the documentation and sample code felt relatively terse and incomplete; not to mention that guesswork (aided by this post) was necessary, when it came to actually integrating it into the build system.

However, once those hurdles are dealt with, basic integration with the Qt project build system simply involves appending the following to the project file:

#Headers for PoCo
HEADERS += /usr/include/Poco/Pipe.h /usr/include/Poco/Process.h \
/usr/include/Poco/PipeStream.h \
/usr/include/Poco/StreamCopier.h

#Libraries for PoCo
LIBS += -lPocoFoundation

Once the project file is configured, adding the following to your class header file (modulo existing references, of course) should work :

#include <QApplication>
#include <QString>
#include <QDebug>

#include <string>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <Poco/Process.h>
#include <Poco/Pipe.h>
#include <Poco/PipeStream.h>
#include <Poco/StreamCopier.h>

using namespace Poco;
using Poco::Process;
using Poco::Pipe;
using Poco::PipeInputStream;
using Poco::PipeOutputStream;
using Poco::ProcessHandle;

Some of the aforementioned header files are unnecessary – although their presence doesn’t seem to cause any obvious problems at compilation or application execution time.

My method in question (a rather rudimentary/brute-force mechanism for returning the MIME type of a file as a QString object, based upon sample code from a presentation slide), looks like: 
QString FileTypeHandler::GetMimeType(QString aFileName) {

    qDebug() << "Inside FileTypeHandler::GetMimeType";
    qDebug() << "Have text: " << aFileName;

    std::string mimeCommand("/usr/bin/file");
    std::vector<std::string> mimeArgs;
    mimeArgs.push_back("-i");
    mimeArgs.push_back(aFileName.toStdString());
    Poco::Pipe mimeOutput;
    ProcessHandle mimeHandle = Process::launch(mimeCommand, mimeArgs, 0, &mimeOutput, 0);
    Poco::PipeInputStream mimeInput(mimeOutput);

    std::string mimeData;

    mimeInput >> mimeData;

    qDebug() << QString::fromStdString(mimeData);

    return QString::fromStdString(mimeData);

}

Theoretically/in essence, it accepts a file name as its argument, invokes the file -i command to (hopefully) look up its MIME type, stores it in a standard ANSI C++ string, and finally returns it as a QString for consumption by UI widgets.

In reality, it pretty much does just that – with the caveat that it doesn’t quite return the correct output. (It returns “/dev/null:” instead of “/dev/null: application/x-character-device; charset=binary“, for example).

Still, I hope that these notes are useful for others who are facing the same problem…

Maybe others can chime in with a better alternative, or other suggestions?