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

tdeio/tdeio

kmimemagic.cpp

00001 /* This file is part of the TDE libraries
00002    Copyright (C) 2014 Timothy Pearson <kb9vqf@pearsoncomputing.net>
00003 
00004    Small portions (the original KDE interface and utime code) are:
00005    Copyright (C) 2000 Fritz Elfert <fritz@kde.org>
00006    Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com>
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Library General Public
00010    License version 2 as published by the Free Software Foundation.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "config.h"
00024 #include "kmimemagic.h"
00025 #include <kdebug.h>
00026 #include <tdeapplication.h>
00027 #include <tqfile.h>
00028 #include <ksimpleconfig.h>
00029 #include <kstandarddirs.h>
00030 #include <kstaticdeleter.h>
00031 #include <klargefile.h>
00032 #include <assert.h>
00033 
00034 #include <magic.h>
00035 
00036 #ifndef MAGIC_MIME_TYPE
00037 #define MAGIC_MIME_TYPE MAGIC_MIME
00038 #endif
00039 
00040 // Taken from file/file.h
00041 // Keep in sync with that header!
00042 #define FILE_LOAD   0
00043 
00044 static void process(struct config_rec* conf,  const TQString &);
00045 
00046 KMimeMagic* KMimeMagic::s_pSelf;
00047 static KStaticDeleter<KMimeMagic> kmimemagicsd;
00048 
00049 KMimeMagic* KMimeMagic::self() {
00050     if( !s_pSelf ) {
00051         initStatic();
00052     }
00053     return s_pSelf;
00054 }
00055 
00056 void KMimeMagic::initStatic() {
00057     s_pSelf = kmimemagicsd.setObject( s_pSelf, new KMimeMagic() );
00058     s_pSelf->setFollowLinks( true );
00059 }
00060 
00061 #include <stdio.h>
00062 #include <unistd.h>
00063 #include <stdlib.h>
00064 #include <sys/wait.h>
00065 #include <sys/types.h>
00066 #include <sys/stat.h>
00067 #include <fcntl.h>
00068 #include <errno.h>
00069 #include <ctype.h>
00070 #include <time.h>
00071 #include <utime.h>
00072 #include <stdarg.h>
00073 #include <tqregexp.h>
00074 #include <tqstring.h>
00075 
00076 #define MIME_INODE_DIR         "inode/directory"
00077 #define MIME_INODE_CDEV        "inode/chardevice"
00078 #define MIME_INODE_BDEV        "inode/blockdevice"
00079 #define MIME_INODE_FIFO        "inode/fifo"
00080 #define MIME_INODE_LINK        "inode/link"
00081 #define MIME_INODE_SOCK        "inode/socket"
00082 #define MIME_BINARY_UNREADABLE "application/x-unreadable"
00083 #define MIME_BINARY_ZEROSIZE   "application/x-zerosize"
00084 
00095 class KMimeMagicUtimeConf {
00096     public:
00097         KMimeMagicUtimeConf() {
00098             tmpDirs << TQString::fromLatin1("/tmp"); // default value
00099 
00100             // The trick is that we also don't want the user to override globally set
00101             // directories. So we have to misuse TDEStandardDirs :}
00102             TQStringList confDirs = TDEGlobal::dirs()->resourceDirs( "config" );
00103             if ( !confDirs.isEmpty() ) {
00104                 TQString globalConf = confDirs.last() + "kmimemagicrc";
00105                 if ( TQFile::exists( globalConf ) ) {
00106                     KSimpleConfig cfg( globalConf );
00107                     cfg.setGroup( "Settings" );
00108                     tmpDirs = cfg.readListEntry( "atimeDirs" );
00109                 }
00110                 if ( confDirs.count() > 1 ) {
00111                     TQString localConf = confDirs.first() + "kmimemagicrc";
00112                     if ( TQFile::exists( localConf ) ) {
00113                         KSimpleConfig cfg( localConf );
00114                         cfg.setGroup( "Settings" );
00115                         tmpDirs += cfg.readListEntry( "atimeDirs" );
00116                     }
00117                 }
00118                 for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it ) {
00119                     TQString dir = *it;
00120                     if ( !dir.isEmpty() && dir[ dir.length()-1 ] != '/' ) {
00121                         (*it) += '/';
00122                     }
00123                 }
00124             }
00125         #if 0
00126             // debug code
00127             for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it ) {
00128                 kdDebug(7018) << " atimeDir: " << *it << endl;
00129             }
00130         #endif
00131         }
00132 
00133         bool restoreAccessTime( const TQString & file ) const {
00134             TQString dir = file.left( file.findRev( '/' ) );
00135             bool res = tmpDirs.contains( dir );
00136             //kdDebug(7018) << "restoreAccessTime " << file << " dir=" << dir << " result=" << res << endl;
00137             return res;
00138         }
00139         TQStringList tmpDirs;
00140 };
00141 
00142 TQString fixupMagicOutput(TQString &mime) {
00143     if (mime == "inode/x-empty") {
00144         return MIME_BINARY_ZEROSIZE;
00145     }
00146     else if (mime.contains("no read permission")) {
00147         return MIME_BINARY_UNREADABLE;
00148     }
00149     else {
00150         return mime;
00151     }
00152 }
00153 
00154 /* current config */
00155 struct config_rec {
00156     bool followLinks;
00157     TQString resultBuf;
00158     int accuracy;
00159 
00160     magic_t magic;
00161     TQStringList databases;
00162 
00163     KMimeMagicUtimeConf * utimeConf;
00164 };
00165 
00166 /*
00167  * apprentice - load configuration from the magic file.
00168  */
00169 int KMimeMagic::apprentice( const TQString& magicfile ) {
00170     TQString maindatabase = magicfile;
00171     if (maindatabase == "") {
00172 #ifdef HAVE_LIBMAGIC_GETPATH
00173         maindatabase = magic_getpath(0, FILE_LOAD);
00174 #else
00175         maindatabase = TQString(LIBMAGIC_PATH);
00176 #endif
00177         if (maindatabase == "") {
00178             kdWarning() << k_funcinfo << "Unable to locate system mime magic database; mime type detection will not function correctly!" << endl;
00179         }
00180     }
00181     conf->databases.clear();
00182     conf->databases.append(maindatabase);
00183     return magic_load(conf->magic, conf->databases[0].latin1());
00184 }
00185 
00186 /*
00187  * magic_process - process input file fn. Opens the file and reads a
00188  * fixed-size buffer to begin processing the contents.
00189  */
00190 
00191 void process(struct config_rec* conf, const TQString & fn) {
00192     KDE_struct_stat sb;
00193         TQCString fileName = TQFile::encodeName( fn );
00194 
00195     int magic_flags = MAGIC_ERROR|MAGIC_MIME_TYPE/*|MAGIC_DEBUG*/;
00196     if (conf->followLinks) {
00197         magic_flags |= MAGIC_SYMLINK;
00198     }
00199     magic_setflags(conf->magic, magic_flags);
00200     conf->resultBuf = TQString(magic_file(conf->magic, fileName));
00201     conf->resultBuf = fixupMagicOutput(conf->resultBuf);
00202 
00203     if ( conf->utimeConf && conf->utimeConf->restoreAccessTime( fn ) ) {
00204         /*
00205         * Try to restore access, modification times if read it.
00206         * This changes the "change" time (ctime), but we can't do anything
00207         * about that.
00208         */
00209         struct utimbuf utbuf;
00210         utbuf.actime = sb.st_atime;
00211         utbuf.modtime = sb.st_mtime;
00212         (void) utime(fileName, &utbuf);
00213     }
00214 }
00215 
00216 KMimeMagic::KMimeMagic() {
00217     // Magic file detection init
00218     TQString mimefile = locate( "mime", "magic" );
00219     init( mimefile );
00220     // Add snippets from share/config/magic/*
00221     TQStringList snippets = TDEGlobal::dirs()->findAllResources( "config", "magic/*.magic", true );
00222     for ( TQStringList::Iterator it = snippets.begin() ; it != snippets.end() ; ++it ) {
00223         if ( !mergeConfig( *it ) ) {
00224             kdWarning() << k_funcinfo << "Failed to parse " << *it << endl;
00225         }
00226     }
00227 }
00228 
00229 KMimeMagic::KMimeMagic(const TQString & _configfile) {
00230     init( _configfile );
00231 }
00232 
00233 void KMimeMagic::init( const TQString& _configfile ) {
00234     int result;
00235     conf = new config_rec;
00236 
00237     /* initialize libmagic */
00238     conf->magic = magic_open(MAGIC_MIME_TYPE);
00239     magicResult = NULL;
00240     conf->followLinks = false;
00241 
00242         conf->utimeConf = 0L; // created on demand
00243     /* on the first time through we read the magic file */
00244     result = apprentice(_configfile);
00245     if (result == -1) {
00246         return;
00247     }
00248 }
00249 
00250 /*
00251  * The destructor.
00252  * Free the magic-table and other resources.
00253  */
00254 KMimeMagic::~KMimeMagic() {
00255     if (conf) {
00256         magic_close(conf->magic);
00257                 delete conf->utimeConf;
00258         delete conf;
00259     }
00260         delete magicResult;
00261 }
00262 
00263 bool KMimeMagic::mergeConfig(const TQString & _configfile) {
00264     conf->databases.append(_configfile);
00265     TQString merged_databases = conf->databases.join(":");
00266 #ifdef MAGIC_VERSION
00267     int magicvers = magic_version();
00268 #else // MAGIC_VERSION
00269     int magicvers = 0;
00270 #endif // MAGIC_VERSION
00271     if ((magicvers < 512) || (magicvers >= 518)) {
00272         if (magic_load(conf->magic, merged_databases.latin1()) == 0) {
00273             return true;
00274         }
00275         else {
00276             return false;
00277         }
00278     }
00279     else {
00280         kdWarning(7018) << k_funcinfo << "KMimeMagic::mergeConfig disabled due to buggy libmagic version " << magicvers << endl;
00281         return false;
00282     }
00283 }
00284 
00285 void KMimeMagic::setFollowLinks( bool _enable ) {
00286     conf->followLinks = _enable;
00287 }
00288 
00289 KMimeMagicResult *KMimeMagic::findBufferType(const TQByteArray &array) {
00290     conf->resultBuf = TQString::null;
00291     if ( !magicResult ) {
00292         magicResult = new KMimeMagicResult();
00293     }
00294     magicResult->setInvalid();
00295     conf->accuracy = 100;
00296 
00297     int nbytes = array.size();
00298     if (nbytes == 0) {
00299         conf->resultBuf = MIME_BINARY_ZEROSIZE;
00300     }
00301     else {
00302         int magic_flags = MAGIC_ERROR|MAGIC_MIME_TYPE/*|MAGIC_DEBUG*/;
00303         if (conf->followLinks) {
00304             magic_flags |= MAGIC_SYMLINK;
00305         }
00306         magic_setflags(conf->magic, magic_flags);
00307         conf->resultBuf = TQString(magic_buffer(conf->magic, array.data(), nbytes));
00308         conf->resultBuf = fixupMagicOutput(conf->resultBuf);
00309     }
00310     /* if we have any results, put them in the request structure */
00311     magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
00312     magicResult->setAccuracy(conf->accuracy);
00313     return magicResult;
00314 }
00315 
00316 static void refineResult(KMimeMagicResult *r, const TQString & _filename) {
00317     TQString tmp = r->mimeType();
00318     if (tmp.isEmpty())
00319         return;
00320     if ( tmp == "text/x-c" || tmp == "text/x-objc" )
00321     {
00322         if ( _filename.right(2) == ".h" )
00323             tmp += "hdr";
00324         else
00325             tmp += "src";
00326         r->setMimeType(tmp);
00327     }
00328     else
00329     if ( tmp == "text/x-c++" )
00330     {
00331         if ( _filename.endsWith(".h")
00332           || _filename.endsWith(".hh")
00333           || _filename.endsWith(".H")
00334           || !_filename.right(4).contains('.'))
00335             tmp += "hdr";
00336         else
00337             tmp += "src";
00338         r->setMimeType(tmp);
00339     }
00340     else
00341     if ( tmp == "application/x-sharedlib" )
00342     {
00343         if ( _filename.find( ".so" ) == -1 ) 
00344         {
00345             tmp = "application/x-executable";
00346             r->setMimeType( tmp );
00347         }
00348     }
00349 }
00350 
00351 KMimeMagicResult *KMimeMagic::findBufferFileType( const TQByteArray &data, const TQString &fn) {
00352         KMimeMagicResult * r = findBufferType( data );
00353     refineResult(r, fn);
00354         return r;
00355 }
00356 
00357 /*
00358  * Find the content-type of the given file.
00359  */
00360 KMimeMagicResult* KMimeMagic::findFileType(const TQString & fn) {
00361 #ifdef DEBUG_MIMEMAGIC
00362     kdDebug(7018) << "KMimeMagic::findFileType " << fn << endl;
00363 #endif
00364     conf->resultBuf = TQString::null;
00365 
00366     if ( !magicResult ) {
00367         magicResult = new KMimeMagicResult();
00368     }
00369     magicResult->setInvalid();
00370     conf->accuracy = 100;
00371 
00372     if ( !conf->utimeConf ) {
00373         conf->utimeConf = new KMimeMagicUtimeConf();
00374     }
00375 
00376     /* process it based on the file contents */
00377     process(conf, fn );
00378 
00379     /* if we have any results, put them in the request structure */
00380     magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
00381     magicResult->setAccuracy(conf->accuracy);
00382     refineResult(magicResult, fn);
00383     return magicResult;
00384 }

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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.7.1
This website is maintained by Timothy Pearson.