• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • kdecore
  • services
kmimemagicrule.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  * Copyright 2007 David Faure <faure@kde.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "kmimemagicrule_p.h"
21 #include <QIODevice>
22 #include <kdebug.h>
23 #include <QByteArrayMatcher>
24 
25 /*
26  * Historical note:
27  * The notion of indents is used differently from the old file(1) magic file.
28  * It is not enough that a top-level rule matches for the search to be over;
29  * in file(1) subrules were used as refinement (and in KMimeMagic they were
30  * mandatory if the toplevel rule didn't have a mimetype associated with it).
31  * Here they are mandatory.
32  * We need at least one continuation at every level to match, and then the match is valid:
33 [50:application/x-kformula]
34 >0=^B^_<8B>
35 1>10=^GKOffice
36 2>18=^Xapplication/x-kformula^D^F
37 >0=^DPK^C^D
38 1>30=^Hmimetype
39 2>38=^Vapplication/x-kformula
40  * Either it's an old (tar) file and the first hierarchy (0,1,2 levels) matches,
41  * or it's a newer file (zip) file and the second hierarchy (0,1,2 levels) has to match.
42  *
43  */
44 
45 static bool testMatches(QIODevice* device, qint64 deviceSize, QByteArray& availableData, const QList<KMimeMagicMatch>& matches, const QString& mimeType)
46 {
47  for ( QList<KMimeMagicMatch>::const_iterator it = matches.begin(), end = matches.end() ;
48  it != end ; ++it ) {
49  const KMimeMagicMatch& match = *it;
50  if (match.match(device, deviceSize, availableData, mimeType)) {
51  // One of the hierarchies matched -> mimetype recognized.
52  return true;
53  }
54  }
55  return false;
56 }
57 
58 // Taken from QByteArray::indexOf, but that one uses strncmp so it stops on '\0',
59 // replaced with memcmp here...
60 static int indexOf(const QByteArray& that, const QByteArray &ba)
61 {
62  const int l = that.size();
63  const int ol = ba.size();
64  if (ol > l)
65  return -1;
66  if (ol == 0)
67  return 0;
68  if (ol == 1)
69  return that.indexOf(*ba.constData());
70 
71  if (l > 500 && ol > 5)
72  return QByteArrayMatcher(ba).indexIn(that);
73 
74  const char *needle = ba.data();
75  const char *haystack = that.data();
76  const char *end = that.data() + (l - ol);
77  const uint ol_minus_1 = ol - 1;
78  uint hashNeedle = 0, hashHaystack = 0;
79  int idx;
80  for (idx = 0; idx < ol; ++idx) {
81  hashNeedle = ((hashNeedle<<1) + needle[idx]);
82  hashHaystack = ((hashHaystack<<1) + haystack[idx]);
83  }
84  hashHaystack -= *(haystack + ol_minus_1);
85 
86  while (haystack <= end) {
87  hashHaystack += *(haystack + ol_minus_1);
88  if (hashHaystack == hashNeedle && *needle == *haystack
89  && memcmp(needle, haystack, ol) == 0)
90  return haystack - that.data();
91 
92  if (ol_minus_1 < sizeof(uint) * 8 /*CHAR_BIT*/)
93  hashHaystack -= (*haystack) << ol_minus_1;
94  hashHaystack <<= 1;
95 
96  ++haystack;
97  }
98  return -1;
99 }
100 
101 
102 bool KMimeMagicRule::match(QIODevice* device, qint64 deviceSize, QByteArray& availableData) const
103 {
104  return testMatches(device, deviceSize, availableData, m_matches, m_mimetype);
105 }
106 
107 bool KMimeMagicMatch::match(QIODevice* device, qint64 deviceSize, QByteArray& availableData, const QString& mimeType) const
108 {
109  // First, check that "this" matches, then we'll dive into subMatches if any.
110 
111  const qint64 mDataSize = m_data.size();
112  if (m_rangeStart + mDataSize > deviceSize)
113  return false; // file is too small
114 
115  // Read in one block all the data we'll need
116  // Example: m_data="ABC", m_rangeLength=3 -> we need 3+3-1=5 bytes (ABCxx,xABCx,xxABC would match)
117  const int dataNeeded = qMin(mDataSize + m_rangeLength - 1, deviceSize - m_rangeStart);
118  QByteArray readData;
119 
120  /*kDebug() << "need " << dataNeeded << " bytes of data starting at " << m_rangeStart
121  << " - availableData has " << availableData.size() << " bytes,"
122  << " device has " << deviceSize << " bytes." << endl;*/
123 
124  if (m_rangeStart + dataNeeded > availableData.size() && availableData.size() < deviceSize) {
125  // Need to read from device
126  if (!device->seek(m_rangeStart))
127  return false;
128  readData.resize(dataNeeded);
129  const int nread = device->read(readData.data(), dataNeeded);
130  //kDebug() << "readData (from device): reading" << dataNeeded << "bytes.";
131  if (nread < mDataSize)
132  return false; // error (or not enough data but we checked for that already)
133  if (m_rangeStart == 0 && readData.size() > availableData.size()) {
134  availableData = readData; // update cache
135  }
136  if (nread < readData.size()) {
137  // File big enough to contain m_data, but not big enough for the full rangeLength.
138  // Pad with zeros.
139  memset(readData.data() + nread, 0, dataNeeded - nread);
140  }
141  //kDebug() << "readData (from device) at pos " << m_rangeStart << ":" << readData;
142  } else {
143  readData = QByteArray::fromRawData(availableData.constData() + m_rangeStart,
144  dataNeeded);
145  // Warning, readData isn't null-terminated so this kDebug
146  // gives valgrind warnings (when printing as char* data).
147  //kDebug() << "readData (from availableData) at pos " << m_rangeStart << ":" << readData;
148  }
149 
150  // All we need to do now, is to look for m_data in readData (whose size is dataNeeded).
151  // Either as a simple indexOf search, or applying the mask.
152 
153  bool found = false;
154  if (m_mask.isEmpty()) {
155  //kDebug() << "m_data=" << m_data;
156  found = ::indexOf(readData, m_data) != -1;
157  //if (found)
158  // kDebug() << "Matched readData=" << readData << "with m_data=" << m_data << "so this is" << mimeType;
159  } else {
160  const char* mask = m_mask.constData();
161  const char* refData = m_data.constData();
162  const char* readDataBase = readData.constData();
163  // Example (continued from above):
164  // deviceSize is 4, so dataNeeded was max'ed to 4.
165  // maxStartPos = 4 - 3 + 1 = 2, and indeed
166  // we need to check for a match a positions 0 and 1 (ABCx and xABC).
167  const qint64 maxStartPos = dataNeeded - mDataSize + 1;
168  for (int i = 0; i < maxStartPos; ++i) {
169  const char* d = readDataBase + i;
170  bool valid = true;
171  for (int off = 0; off < mDataSize; ++off ) {
172  if ( ((*d++) & mask[off]) != ((refData[off] & mask[off])) ) {
173  valid = false;
174  break;
175  }
176  }
177  if (valid)
178  found = true;
179  }
180  }
181  if (!found)
182  return false;
183 
184  // No submatch? Then we are done.
185  if (m_subMatches.isEmpty())
186  return true;
187 
188  // Check that one of the submatches matches too
189  return testMatches(device, deviceSize, availableData, m_subMatches, mimeType);
190 }
QIODevice
KMimeMagicMatch::m_mask
QByteArray m_mask
Definition: kmimemagicrule_p.h:38
qint64
kdebug.h
kmimemagicrule_p.h
QByteArrayMatcher::indexIn
int indexIn(const QByteArray &ba, int from) const
QIODevice::seek
virtual bool seek(qint64 pos)
QByteArray
mask
#define mask
QByteArray::isEmpty
bool isEmpty() const
QByteArray::fromRawData
QByteArray fromRawData(const char *data, int size)
KMimeMagicRule::match
bool match(QIODevice *device, qint64 deviceSize, QByteArray &availableData) const
Definition: kmimemagicrule.cpp:102
QByteArray::resize
void resize(int size)
QByteArray::indexOf
int indexOf(char ch, int from) const
KMimeMagicMatch::m_data
QByteArray m_data
Definition: kmimemagicrule_p.h:37
QList::isEmpty
bool isEmpty() const
QByteArray::constData
const char * constData() const
QIODevice::read
qint64 read(char *data, qint64 maxSize)
KMimeMagicMatch::match
bool match(QIODevice *device, qint64 deviceSize, QByteArray &availableData, const QString &mimeType) const
Definition: kmimemagicrule.cpp:107
QString
QList< KMimeMagicMatch >
testMatches
static bool testMatches(QIODevice *device, qint64 deviceSize, QByteArray &availableData, const QList< KMimeMagicMatch > &matches, const QString &mimeType)
Definition: kmimemagicrule.cpp:45
QList::end
iterator end()
KMimeMagicMatch::m_rangeLength
qint64 m_rangeLength
Definition: kmimemagicrule_p.h:36
QByteArrayMatcher
KMimeMagicMatch::m_rangeStart
qint64 m_rangeStart
Definition: kmimemagicrule_p.h:35
QByteArray::data
char * data()
KMimeMagicMatch::m_subMatches
QList< KMimeMagicMatch > m_subMatches
Definition: kmimemagicrule_p.h:39
QByteArray::size
int size() const
KMimeMagicMatch
Definition: kmimemagicrule_p.h:31
QList::begin
iterator begin()
indexOf
static int indexOf(const QByteArray &that, const QByteArray &ba)
Definition: kmimemagicrule.cpp:60
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal