• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

  • tdeio
  • tdeio
kmimemagic.cpp
1 /* This file is part of the TDE libraries
2  Copyright (C) 2014 Timothy Pearson <kb9vqf@pearsoncomputing.net>
3 
4  Small portions (the original KDE interface and utime code) are:
5  Copyright (C) 2000 Fritz Elfert <fritz@kde.org>
6  Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com>
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License version 2 as published by the Free Software Foundation.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
22 
23 #include "config.h"
24 #include "kmimemagic.h"
25 #include <kdebug.h>
26 #include <tdeapplication.h>
27 #include <tqfile.h>
28 #include <ksimpleconfig.h>
29 #include <kstandarddirs.h>
30 #include <kstaticdeleter.h>
31 #include <klargefile.h>
32 #include <assert.h>
33 
34 #include <magic.h>
35 
36 #ifndef MAGIC_MIME_TYPE
37 #define MAGIC_MIME_TYPE MAGIC_MIME
38 #endif
39 
40 // Taken from file/file.h
41 // Keep in sync with that header!
42 #define FILE_LOAD 0
43 
44 static void process(struct config_rec* conf, const TQString &);
45 
46 KMimeMagic* KMimeMagic::s_pSelf;
47 static KStaticDeleter<KMimeMagic> kmimemagicsd;
48 
49 KMimeMagic* KMimeMagic::self() {
50  if( !s_pSelf ) {
51  initStatic();
52  }
53  return s_pSelf;
54 }
55 
56 void KMimeMagic::initStatic() {
57  s_pSelf = kmimemagicsd.setObject( s_pSelf, new KMimeMagic() );
58  s_pSelf->setFollowLinks( true );
59 }
60 
61 #include <stdio.h>
62 #include <unistd.h>
63 #include <stdlib.h>
64 #include <sys/wait.h>
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <fcntl.h>
68 #include <errno.h>
69 #include <ctype.h>
70 #include <time.h>
71 #include <utime.h>
72 #include <stdarg.h>
73 #include <tqregexp.h>
74 #include <tqstring.h>
75 
76 #define MIME_INODE_DIR "inode/directory"
77 #define MIME_INODE_CDEV "inode/chardevice"
78 #define MIME_INODE_BDEV "inode/blockdevice"
79 #define MIME_INODE_FIFO "inode/fifo"
80 #define MIME_INODE_LINK "inode/link"
81 #define MIME_INODE_SOCK "inode/socket"
82 #define MIME_BINARY_UNREADABLE "application/x-unreadable"
83 #define MIME_BINARY_ZEROSIZE "application/x-zerosize"
84 
95 class KMimeMagicUtimeConf {
96  public:
97  KMimeMagicUtimeConf() {
98  tmpDirs << TQString::fromLatin1("/tmp"); // default value
99 
100  // The trick is that we also don't want the user to override globally set
101  // directories. So we have to misuse TDEStandardDirs :}
102  TQStringList confDirs = TDEGlobal::dirs()->resourceDirs( "config" );
103  if ( !confDirs.isEmpty() ) {
104  TQString globalConf = confDirs.last() + "kmimemagicrc";
105  if ( TQFile::exists( globalConf ) ) {
106  KSimpleConfig cfg( globalConf );
107  cfg.setGroup( "Settings" );
108  tmpDirs = cfg.readListEntry( "atimeDirs" );
109  }
110  if ( confDirs.count() > 1 ) {
111  TQString localConf = confDirs.first() + "kmimemagicrc";
112  if ( TQFile::exists( localConf ) ) {
113  KSimpleConfig cfg( localConf );
114  cfg.setGroup( "Settings" );
115  tmpDirs += cfg.readListEntry( "atimeDirs" );
116  }
117  }
118  for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it ) {
119  TQString dir = *it;
120  if ( !dir.isEmpty() && dir[ dir.length()-1 ] != '/' ) {
121  (*it) += '/';
122  }
123  }
124  }
125  #if 0
126  // debug code
127  for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it ) {
128  kdDebug(7018) << " atimeDir: " << *it << endl;
129  }
130  #endif
131  }
132 
133  bool restoreAccessTime( const TQString & file ) const {
134  TQString dir = file.left( file.findRev( '/' ) );
135  bool res = tmpDirs.contains( dir );
136  //kdDebug(7018) << "restoreAccessTime " << file << " dir=" << dir << " result=" << res << endl;
137  return res;
138  }
139  TQStringList tmpDirs;
140 };
141 
142 TQString fixupMagicOutput(TQString &mime) {
143  if (mime == "inode/x-empty") {
144  return MIME_BINARY_ZEROSIZE;
145  }
146  else if (mime.contains("no read permission")) {
147  return MIME_BINARY_UNREADABLE;
148  }
149  else {
150  return mime;
151  }
152 }
153 
154 /* current config */
155 struct config_rec {
156  bool followLinks;
157  TQString resultBuf;
158  int accuracy;
159 
160  magic_t magic;
161  TQStringList databases;
162 
163  KMimeMagicUtimeConf * utimeConf;
164 };
165 
166 /*
167  * apprentice - load configuration from the magic file.
168  */
169 int KMimeMagic::apprentice( const TQString& magicfile ) {
170  TQString maindatabase = magicfile;
171  if (maindatabase == "") {
172 #ifdef HAVE_LIBMAGIC_GETPATH
173  maindatabase = magic_getpath(0, FILE_LOAD);
174 #else
175  maindatabase = TQString(LIBMAGIC_PATH);
176 #endif
177  if (maindatabase == "") {
178  kdWarning() << k_funcinfo << "Unable to locate system mime magic database; mime type detection will not function correctly!" << endl;
179  }
180  }
181  conf->databases.clear();
182  conf->databases.append(maindatabase);
183  return magic_load(conf->magic, conf->databases[0].latin1());
184 }
185 
186 /*
187  * magic_process - process input file fn. Opens the file and reads a
188  * fixed-size buffer to begin processing the contents.
189  */
190 
191 void process(struct config_rec* conf, const TQString & fn) {
192  KDE_struct_stat sb;
193  TQCString fileName = TQFile::encodeName( fn );
194 
195  int magic_flags = MAGIC_ERROR|MAGIC_MIME_TYPE/*|MAGIC_DEBUG*/;
196  if (conf->followLinks) {
197  magic_flags |= MAGIC_SYMLINK;
198  }
199  magic_setflags(conf->magic, magic_flags);
200  conf->resultBuf = TQString(magic_file(conf->magic, fileName));
201  conf->resultBuf = fixupMagicOutput(conf->resultBuf);
202 
203  if ( conf->utimeConf && conf->utimeConf->restoreAccessTime( fn ) ) {
204  /*
205  * Try to restore access, modification times if read it.
206  * This changes the "change" time (ctime), but we can't do anything
207  * about that.
208  */
209  struct utimbuf utbuf;
210  utbuf.actime = sb.st_atime;
211  utbuf.modtime = sb.st_mtime;
212  (void) utime(fileName, &utbuf);
213  }
214 }
215 
216 KMimeMagic::KMimeMagic() {
217  // Magic file detection init
218  TQString mimefile = locate( "mime", "magic" );
219  init( mimefile );
220  // Add snippets from share/config/magic/*
221  TQStringList snippets = TDEGlobal::dirs()->findAllResources( "config", "magic/*.magic", true );
222  for ( TQStringList::Iterator it = snippets.begin() ; it != snippets.end() ; ++it ) {
223  if ( !mergeConfig( *it ) ) {
224  kdWarning() << k_funcinfo << "Failed to parse " << *it << endl;
225  }
226  }
227 }
228 
229 KMimeMagic::KMimeMagic(const TQString & _configfile) {
230  init( _configfile );
231 }
232 
233 void KMimeMagic::init( const TQString& _configfile ) {
234  int result;
235  conf = new config_rec;
236 
237  /* initialize libmagic */
238  conf->magic = magic_open(MAGIC_MIME_TYPE);
239  magicResult = NULL;
240  conf->followLinks = false;
241 
242  conf->utimeConf = 0L; // created on demand
243  /* on the first time through we read the magic file */
244  result = apprentice(_configfile);
245  if (result == -1) {
246  return;
247  }
248 }
249 
250 /*
251  * The destructor.
252  * Free the magic-table and other resources.
253  */
254 KMimeMagic::~KMimeMagic() {
255  if (conf) {
256  magic_close(conf->magic);
257  delete conf->utimeConf;
258  delete conf;
259  }
260  delete magicResult;
261 }
262 
263 bool KMimeMagic::mergeConfig(const TQString & _configfile) {
264  conf->databases.append(_configfile);
265  TQString merged_databases = conf->databases.join(":");
266 #ifdef MAGIC_VERSION
267  int magicvers = magic_version();
268 #else // MAGIC_VERSION
269  int magicvers = 0;
270 #endif // MAGIC_VERSION
271  if ((magicvers < 512) || (magicvers >= 518)) {
272  if (magic_load(conf->magic, merged_databases.latin1()) == 0) {
273  return true;
274  }
275  else {
276  return false;
277  }
278  }
279  else {
280  kdWarning(7018) << k_funcinfo << "KMimeMagic::mergeConfig disabled due to buggy libmagic version " << magicvers << endl;
281  return false;
282  }
283 }
284 
285 void KMimeMagic::setFollowLinks( bool _enable ) {
286  conf->followLinks = _enable;
287 }
288 
289 KMimeMagicResult *KMimeMagic::findBufferType(const TQByteArray &array) {
290  conf->resultBuf = TQString::null;
291  if ( !magicResult ) {
292  magicResult = new KMimeMagicResult();
293  }
294  magicResult->setInvalid();
295  conf->accuracy = 100;
296 
297  int nbytes = array.size();
298  if (nbytes == 0) {
299  conf->resultBuf = MIME_BINARY_ZEROSIZE;
300  }
301  else {
302  int magic_flags = MAGIC_ERROR|MAGIC_MIME_TYPE/*|MAGIC_DEBUG*/;
303  if (conf->followLinks) {
304  magic_flags |= MAGIC_SYMLINK;
305  }
306  magic_setflags(conf->magic, magic_flags);
307  conf->resultBuf = TQString(magic_buffer(conf->magic, array.data(), nbytes));
308  conf->resultBuf = fixupMagicOutput(conf->resultBuf);
309  }
310  /* if we have any results, put them in the request structure */
311  magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
312  magicResult->setAccuracy(conf->accuracy);
313  return magicResult;
314 }
315 
316 static void refineResult(KMimeMagicResult *r, const TQString & _filename) {
317  TQString tmp = r->mimeType();
318  if (tmp.isEmpty())
319  return;
320  if ( tmp == "text/x-c" || tmp == "text/x-objc" )
321  {
322  if ( _filename.right(2) == ".h" )
323  tmp += "hdr";
324  else
325  tmp += "src";
326  r->setMimeType(tmp);
327  }
328  else
329  if ( tmp == "text/x-c++" )
330  {
331  if ( _filename.endsWith(".h")
332  || _filename.endsWith(".hh")
333  || _filename.endsWith(".H")
334  || !_filename.right(4).contains('.'))
335  tmp += "hdr";
336  else
337  tmp += "src";
338  r->setMimeType(tmp);
339  }
340  else
341  if ( tmp == "application/x-sharedlib" )
342  {
343  if ( _filename.find( ".so" ) == -1 )
344  {
345  tmp = "application/x-executable";
346  r->setMimeType( tmp );
347  }
348  }
349 }
350 
351 KMimeMagicResult *KMimeMagic::findBufferFileType( const TQByteArray &data, const TQString &fn) {
352  KMimeMagicResult * r = findBufferType( data );
353  refineResult(r, fn);
354  return r;
355 }
356 
357 /*
358  * Find the content-type of the given file.
359  */
360 KMimeMagicResult* KMimeMagic::findFileType(const TQString & fn) {
361 #ifdef DEBUG_MIMEMAGIC
362  kdDebug(7018) << "KMimeMagic::findFileType " << fn << endl;
363 #endif
364  conf->resultBuf = TQString::null;
365 
366  if ( !magicResult ) {
367  magicResult = new KMimeMagicResult();
368  }
369  magicResult->setInvalid();
370  conf->accuracy = 100;
371 
372  if ( !conf->utimeConf ) {
373  conf->utimeConf = new KMimeMagicUtimeConf();
374  }
375 
376  /* process it based on the file contents */
377  process(conf, fn );
378 
379  /* if we have any results, put them in the request structure */
380  magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
381  magicResult->setAccuracy(conf->accuracy);
382  refineResult(magicResult, fn);
383  return magicResult;
384 }
KMimeMagic::magicResult
KMimeMagicResult * magicResult
The result type.
Definition: kmimemagic.h:189
KMimeMagicResult::mimeType
TQString mimeType() const
Retrieve the mimetype (e.g.
Definition: kmimemagic.h:55
KMimeMagic::findFileType
KMimeMagicResult * findFileType(const TQString &_filename)
Try to find a MimeType for the given file.
Definition: kmimemagic.cpp:360
KMimeMagic::findBufferFileType
KMimeMagicResult * findBufferFileType(const TQByteArray &, const TQString &filename)
Same functionality as findBufferType() but with additional capability of distinguishing between C-hea...
Definition: kmimemagic.cpp:351
KMimeMagic::setFollowLinks
void setFollowLinks(bool _enable)
Enable/Disable follow-links.
Definition: kmimemagic.cpp:285
KMimeMagic::self
static KMimeMagic * self()
Returns a pointer to the unique KMimeMagic instance in this process.
Definition: kmimemagic.cpp:49
KMimeMagic::~KMimeMagic
~KMimeMagic()
Destroy the parser.
Definition: kmimemagic.cpp:254
KMimeMagic::mergeConfig
bool mergeConfig(const TQString &configFile)
Merge an existing parse table with the data from the given file.
Definition: kmimemagic.cpp:263
KMimeMagic::KMimeMagic
KMimeMagic()
Create a parser and initialize it with the KDE-global data: the "magic" config file as well as the sn...
Definition: kmimemagic.cpp:216
KMimeMagicResult
Definition: kmimemagic.h:46
KMimeMagic::findBufferType
KMimeMagicResult * findBufferType(const TQByteArray &p)
Same functionality as above, except data is not read from a file.
Definition: kmimemagic.cpp:289
KMimeMagic
Definition: kmimemagic.h:101

tdeio/tdeio

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

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.8.8
This website is maintained by Timothy Pearson.