KDECore
kmimemagicrule.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kmimemagicrule_p.h"
00021 #include <QIODevice>
00022 #include <kdebug.h>
00023 #include <QByteArrayMatcher>
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 static bool testMatches(QIODevice* device, QByteArray& availableData, const QList<KMimeMagicMatch>& matches, const QString& mimeType)
00046 {
00047 for ( QList<KMimeMagicMatch>::const_iterator it = matches.begin(), end = matches.end() ;
00048 it != end ; ++it ) {
00049 const KMimeMagicMatch& match = *it;
00050 if (match.match(device, availableData, mimeType)) {
00051
00052 return true;
00053 }
00054 }
00055 return false;
00056 }
00057
00058
00059
00060 static int indexOf(const QByteArray& that, const QByteArray &ba)
00061 {
00062 const int l = that.size();
00063 const int ol = ba.size();
00064 if (ol > l)
00065 return -1;
00066 if (ol == 0)
00067 return 0;
00068 if (ol == 1)
00069 return that.indexOf(*ba.constData());
00070
00071 if (l > 500 && ol > 5)
00072 return QByteArrayMatcher(ba).indexIn(that);
00073
00074 const char *needle = ba.data();
00075 const char *haystack = that.data();
00076 const char *end = that.data() + (l - ol);
00077 const uint ol_minus_1 = ol - 1;
00078 uint hashNeedle = 0, hashHaystack = 0;
00079 int idx;
00080 for (idx = 0; idx < ol; ++idx) {
00081 hashNeedle = ((hashNeedle<<1) + needle[idx]);
00082 hashHaystack = ((hashHaystack<<1) + haystack[idx]);
00083 }
00084 hashHaystack -= *(haystack + ol_minus_1);
00085
00086 while (haystack <= end) {
00087 hashHaystack += *(haystack + ol_minus_1);
00088 if (hashHaystack == hashNeedle && *needle == *haystack
00089 && memcmp(needle, haystack, ol) == 0)
00090 return haystack - that.data();
00091
00092 if (ol_minus_1 < sizeof(uint) * 8 )
00093 hashHaystack -= (*haystack) << ol_minus_1;
00094 hashHaystack <<= 1;
00095
00096 ++haystack;
00097 }
00098 return -1;
00099 }
00100
00101
00102 bool KMimeMagicRule::match(QIODevice* device, QByteArray& availableData) const
00103 {
00104 return testMatches(device, availableData, m_matches, m_mimetype);
00105 }
00106
00107 bool KMimeMagicMatch::match(QIODevice* device, QByteArray& availableData, const QString& mimeType) const
00108 {
00109
00110
00111 const qint64 deviceSize = device->size();
00112 const qint64 mDataSize = m_data.size();
00113 if (m_rangeStart + mDataSize > deviceSize)
00114 return false;
00115
00116
00117
00118 const int dataNeeded = qMin(mDataSize + m_rangeLength - 1, deviceSize - m_rangeStart);
00119 QByteArray readData;
00120
00121
00122
00123
00124
00125 if (m_rangeStart + dataNeeded > availableData.size() && availableData.size() < deviceSize) {
00126
00127 if (!device->seek(m_rangeStart))
00128 return false;
00129 readData.resize(dataNeeded);
00130 const int nread = device->read(readData.data(), dataNeeded);
00131
00132 if (nread < mDataSize)
00133 return false;
00134 if (m_rangeStart == 0 && readData.size() > availableData.size()) {
00135 availableData = readData;
00136 }
00137 if (nread < readData.size()) {
00138
00139
00140 memset(readData.data() + nread, 0, dataNeeded - nread);
00141 }
00142
00143 } else {
00144 readData = QByteArray::fromRawData(availableData.constData() + m_rangeStart,
00145 dataNeeded);
00146
00147
00148
00149 }
00150
00151
00152
00153
00154 bool found = false;
00155 if (m_mask.isEmpty()) {
00156
00157 found = ::indexOf(readData, m_data) != -1;
00158
00159
00160 } else {
00161 const char* mask = m_mask.constData();
00162 const char* refData = m_data.constData();
00163 const char* readDataBase = readData.constData();
00164
00165
00166
00167
00168 const qint64 maxStartPos = dataNeeded - mDataSize + 1;
00169 for (int i = 0; i < maxStartPos; ++i) {
00170 const char* d = readDataBase + i;
00171 bool valid = true;
00172 for (int off = 0; off < mDataSize; ++off ) {
00173 if ( ((*d++) & mask[off]) != ((refData[off] & mask[off])) ) {
00174 valid = false;
00175 break;
00176 }
00177 }
00178 if (valid)
00179 found = true;
00180 }
00181 }
00182 if (!found)
00183 return false;
00184
00185
00186 if (m_subMatches.isEmpty())
00187 return true;
00188
00189
00190 return testMatches(device, availableData, m_subMatches, mimeType);
00191 }