1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
3 * This program is free software. It comes without any warranty, to
4 * the extent permitted by applicable law. You can redistribute it
5 * and/or modify it under the terms of the Do What The Fuck You Want
6 * To Public License, Version 2, as published by Sam Hocevar. See
7 * http://sam.zoy.org/wtfpl/COPYING for more details.
12 #include "xcrthemefx.h"
17 #include <QStringList>
18 #include <QTextStream>
25 static const char *curShapeName
[] = {
27 "help arrow (the one with '?')",
34 "north (vert) resize",
36 "west (vert-means horiz?) resize",
49 ///////////////////////////////////////////////////////////////////////////////
50 static QByteArray
zlibInflate (const void *buf
, int bufSz
, int destSz
) {
56 stream
.next_in
= (Bytef
*)buf
;
57 stream
.avail_in
= bufSz
;
58 stream
.zalloc
= (alloc_func
)0;
59 stream
.zfree
= (free_func
)0;
60 stream
.next_out
= (Bytef
*)res
.data();
61 stream
.avail_out
= destSz
;
63 err
= inflateInit(&stream
);
64 if (err
!= Z_OK
) return QByteArray();
65 err
= inflate(&stream
, Z_SYNC_FLUSH
);
66 fprintf(stderr
, "inflate result: %i\n", err
);
69 err
= inflateEnd(&stream
);
70 fprintf(stderr
, "Z_STREAM_END: inflate result: %i\n", err
);
71 if (err
!= Z_OK
) return QByteArray();
74 err
= inflateEnd(&stream
);
75 fprintf(stderr
, "Z_OK: inflate result: %i\n", err
);
76 if (err
!= Z_OK
) return QByteArray();
78 default: return QByteArray();
84 static quint32
baGetDW (QByteArray
&ba
, int &pos
) {
85 const uchar
*d
= (const uchar
*)ba
.constData();
89 for (int f
= 4; f
> 0; f
--, d
--) {
97 ///////////////////////////////////////////////////////////////////////////////
98 XCursorThemeFX::XCursorThemeFX (const QString
&aFileName
) : XCursorTheme() {
99 if (!parseCursorFXTheme(aFileName
)) {
106 bool XCursorThemeFX::parseCursorFXTheme (const QString
&aFileName
) {
107 qDebug() << "loading" << aFileName
;
109 if (!fl
.open(QIODevice::ReadOnly
)) return false; // shit!
110 QByteArray
ba(fl
.readAll());
112 if (ba
.size() < 0xb8) return false; // shit!
114 if (baGetDW(ba
, pos
) != 1) return false; // invalid version
115 quint32 mainHdrSize
= baGetDW(ba
, pos
);
116 if (mainHdrSize
< 0xb8) return false; // invalid header size
117 quint32 unDataSize
= baGetDW(ba
, pos
);
118 if (unDataSize
< 0x4c) return false; // no cursors anyway
124 for (int f
= 0; f
< 6; f
++) {
125 infoFields
[f
].ofs
= baGetDW(ba
, pos
);
126 infoFields
[f
].len
= baGetDW(ba
, pos
);
129 quint32 ihdrSize
= baGetDW(ba
, pos
);
132 qDebug() << "reading data from" << pos
;
133 QByteArray
unp(zlibInflate(ba
.constData()+pos
, ba
.size()-pos
, unDataSize
));
135 qWarning() << "CursorFX: can't depack data";
140 qDebug() << "resources started at hex" << QString::number(pos
, 16);
141 while (pos
<= unp
.size()-12) {
142 quint32 ipos
= pos
; // will be fixed later
143 quint32 rtype
= baGetDW(unp
, pos
);
144 quint32 basicHdrSize
= baGetDW(unp
, pos
);
145 quint32 itemSize
= baGetDW(unp
, pos
);
146 qDebug() << "pos hex:" << QString::number(pos
, 16) << "rtype:" << rtype
<< "bhdrsz hex:" << QString::number(basicHdrSize
, 16) << "itemsz hex:" << QString::number(itemSize
, 16);
149 qWarning() << "CursorFX: invalid data chunk size";
152 pos
= ipos
+itemSize
; // skip it
153 if (rtype
!= 2) continue; // not cursor resource
154 if (itemSize
< 0x4c) {
155 qWarning() << "CursorFX: invalid cursor chunk size:" << itemSize
;
160 rtype
= baGetDW(unp
, cps
);
162 qWarning() << "CursorFX: invalid cursor chunk type:" << rtype
;
165 quint32 curShape
= baGetDW(unp
, cps
);
166 quint32 curType
= baGetDW(unp
, cps
);
168 qWarning() << "CursorFX: unknown cursor shape:" << curShape
;
172 qDebug() << "skiping 'press' cursor; shape no" << curShape
<< "named" << curShapeName
[curShape
];
174 // we need only 'normal' cursors
176 qDebug() << "cursor shape:" << curShape
;
177 const char **nlst
= findCursorByFXId((int)curShape
);
179 // unknown cursor type, skip it
180 qWarning() << "CursorFX: skiping cursor shape:" << curShapeName
[curShape
];
183 qDebug() << "importing cursor" << *nlst
;
184 cps
+= 4; // skip unknown field
185 quint32 frameCnt
= baGetDW(unp
, cps
);
186 if (frameCnt
< 1) frameCnt
= 1; // just in case
187 quint32 imgWdt
= baGetDW(unp
, cps
);
188 quint32 imgHgt
= baGetDW(unp
, cps
);
189 quint32 imgDelay
= baGetDW(unp
, cps
);
190 quint32 aniFlags
= baGetDW(unp
, cps
);
191 cps
+= 4; // skip unknown field
192 quint32 imgXHot
= baGetDW(unp
, cps
);
193 quint32 imgYHot
= baGetDW(unp
, cps
);
194 quint32 realHdrSize
= baGetDW(unp
, cps
);
195 quint32 imgDataSize
= baGetDW(unp
, cps
);
196 quint32 addonOfs
= baGetDW(unp
, cps
);
197 quint32 addonLen
= baGetDW(unp
, cps
);
200 "\n frames:" << frameCnt
<<
201 "\n width:" << imgWdt
<<
202 "\n height:" << imgHgt
<<
203 "\n delay:" << imgDelay
<<
204 "\n flags:" << QString::number(aniFlags
, 2) <<
205 "\n xhot:" << imgXHot
<<
206 "\n yhot:" << imgYHot
208 // now check if we have enought data
209 if (ipos
+realHdrSize
+imgDataSize
> (quint32
)pos
) {
210 qWarning() << "CursorFX: cursor data too big";
213 // addon is the script; parse it later
216 if (addonOfs
< 0x4c || addonOfs
> realHdrSize
) {
217 qWarning() << "CursorFX: invalid addon data offset";
220 QByteArray
bs(unp
.mid(addonOfs
, addonLen
));
221 bs
.append('\0'); bs
.append('\0');
222 script
= QString::fromUtf16((const ushort
*)bs
.constData());
223 qDebug() << "script:\n" << script
;
226 QImage
img((const uchar
*)unp
.constData()+ihdrSize
+realHdrSize
, imgWdt
, imgHgt
, QImage::Format_ARGB32
/*_Premultiplied*/);
227 //mImage = new QImage(img.copy());
228 XCursorImages
*cim
= new XCursorImages(*nlst
);
229 quint32 frameWdt
= img
.width()/frameCnt
, frX
= 0;
230 for (quint32 f
= 0; f
< frameCnt
; f
++) {
231 QImage frame
= img
.copy(frX
, 0, frameWdt
, img
.height());
232 frX
+= frameWdt
; // next frame
233 XCursorImage
*i
= new XCursorImage(QString("%1%2").arg(cim
->name()).arg(QString::number(f
)),
234 frame
, imgXHot
, imgYHot
, imgDelay
, 1