/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) * (c)DWTFYW * * This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ #include //#include #include "xcrxcur.h" #include #include #include #include #include #include #include #include #include /* static QImage autoCropImage (const QImage &image) { // Compute an autocrop rectangle for the image QRect r(image.rect().bottomRight(), image.rect().topLeft()); const quint32 *pixels = reinterpret_cast(image.bits()); for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { if (*(pixels++)) { if (x < r.left()) r.setLeft(x); if (x > r.right()) r.setRight(x); if (y < r.top()) r.setTop(y); if (y > r.bottom()) r.setBottom(y); } } } // Normalize the rectangle return image.copy(r.normalized()); } */ inline static quint32 getDW (const void *data) { const quint8 *d = (const quint8 *)data; d += 3; quint32 res = 0; for (int f = 4; f > 0; f--, d--) { res <<= 8; res |= *d; } return res; } static quint32 baGetDW (QByteArray &ba, int &pos) { const uchar *d = (const uchar *)ba.constData(); d += pos+3; pos += 4; quint32 res = 0; for (int f = 4; f > 0; f--, d--) { res <<= 8; res |= *d; } return res; } /////////////////////////////////////////////////////////////////////////////// XCursorImageXCur::XCursorImageXCur (const QString &aName, const void *aImgData) : XCursorImage(aName) { parseImgData(aImgData); } XCursorImageXCur::~XCursorImageXCur () { } void XCursorImageXCur::parseImgData (const void *aImgData) { mIsValid = false; delete mImage; // It's fine to delete a null pointer mImage = 0; const quint32 *data = (const quint32 *)aImgData; if (getDW(data) != 36) return; // header size if (getDW(data+1) != 0xfffd0002L) return; // magic //if (getDW(data+2) != 1) return; // image subtype if (getDW(data+3) != 1) return; // version mCSize = getDW(data+2); data += 4; quint32 wdt = getDW(data++); // width quint32 hgt = getDW(data++); // height if (wdt > 0x7fff) return; if (hgt > 0x7fff) return; /* quint32 xhot = getDW(data++); quint32 yhot = getDW(data++); assert(xhot <= wdt); assert(yhot <= hgt); */ mXHot = *((const qint32 *)data); data++; mYHot = *((const qint32 *)data); data++; mDelay = getDW(data++); // milliseconds // got to pixels (ARGB) QImage img((const uchar *)data, wdt, hgt, QImage::Format_ARGB32_Premultiplied); mImage = new QImage(img.copy()); mIsValid = true; } /////////////////////////////////////////////////////////////////////////////// XCursorImagesXCur::XCursorImagesXCur (const QDir &aDir, const QString &aName) : XCursorImages(aName, aDir.path()) { parseCursorFile(aDir.path()+"/"+aName); } XCursorImagesXCur::XCursorImagesXCur (const QString &aFileName) : XCursorImages("", "") { QString name(aFileName); if (name.isEmpty() || name.endsWith('/')) return; int i = name.lastIndexOf('/'); QString dir; if (i < 0) dir = "./"; else dir = name.left(i); name = name.mid(i+1); setName(name); setPath(dir); parseCursorFile(aFileName); } bool XCursorImagesXCur::parseCursorFile (const QString &fname) { //qDebug() << fname; qDeleteAll(mList); mList.clear(); QFile fl(fname); if (!fl.open(QIODevice::ReadOnly)) return false; // shit! QByteArray ba(fl.readAll()); fl.close(); if (ba.size() < 4*4) return false; // shit! if (ba[0] != 'X' || ba[1] != 'c' || ba[2] != 'u' || ba[3] != 'r') return false; // shit! //FIXME: add more checks! int pos = 4; quint32 hdrSize = baGetDW(ba, pos); if (hdrSize < 16) return false; // invalid header size quint32 version = baGetDW(ba, pos); if (version != 65536) return false; // invalid version quint32 ntoc = baGetDW(ba, pos); if (!ntoc) return true; // nothing to parse if (ntoc >= 65536) return false; // idiot or what? quint32 tocEndOfs = hdrSize+(ntoc*(3*4)); if (tocEndOfs > (quint32)ba.size()) return false; // out of data pos = hdrSize; // parse TOC int cnt = -1; bool wasTitle = false, wasAuthor = false, wasLic = false; bool wasMail = false, wasSite = false, wasDescr = false, wasIM = false; while (ntoc-- > 0) { cnt++; quint32 type = baGetDW(ba, pos); pos += 4; // skip the shit quint32 dataOfs = baGetDW(ba, pos); if (type == 0xfffd0001) { // text if (dataOfs < tocEndOfs || dataOfs > (quint32)ba.size()-20) continue; // invalid text // parse text int ipos = dataOfs; if (baGetDW(ba, ipos) != 20) continue; // invalid header size if (baGetDW(ba, ipos) != 0xfffd0001) continue; // invalid type quint32 subT = baGetDW(ba, ipos); if (baGetDW(ba, ipos) != 1) continue; // invalid version quint32 len = baGetDW(ba, ipos); // check for data presence if (ipos+len > (quint32)ba.size()) continue; // out of data QByteArray stBA(ba.mid(ipos, len)); QString s(QString::fromUtf8(stBA)); switch (subT) { case 1: // copyright (author) if (!wasAuthor) { wasAuthor = true; mAuthor = s; } break; case 2: // license if (!wasLic) { wasLic = true; mLicense = s; } break; case 3: // other (description) if (!wasDescr) { wasDescr = true; mDescr = s; } break; // my extensions case 4: // title if (!wasTitle) { wasTitle = true; mTitle = s; } break; case 5: // e-mail if (!wasMail) { wasMail = true; mEMail = s; } break; case 6: // site if (!wasSite) { wasSite = true; mSite = s; } break; case 7: // IM if (!wasIM) { wasIM = true; mIM = s; } break; } continue; } if (type != 0xfffd0002) continue; // not an image, skip this one // image // check if (dataOfs < tocEndOfs || dataOfs > (quint32)ba.size()-36) continue; // invalid image // parse image int ipos = dataOfs; if (baGetDW(ba, ipos) != 36) continue; // invalid image (header size) if (baGetDW(ba, ipos) != 0xfffd0002) continue; // invalid type ipos += 4; // skip the shit if (baGetDW(ba, ipos) != 1) continue; // invalid image (version) quint32 wdt = baGetDW(ba, ipos); quint32 hgt = baGetDW(ba, ipos); if (wdt > 0x7fff || hgt > 0x7fff) continue; // invalid sizes // check for data presence if ((ipos+3*4)+(wdt*hgt*4) > (quint32)ba.size()) continue; // out of data // load image const uchar *dta = (const uchar *)ba.constData(); dta += dataOfs; XCursorImage *img = new XCursorImageXCur(mName+"_"+QString::number(cnt), dta); if (img->isValid()) mList << img; else delete img; } return true; }