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:
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:
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.


