Parent: [ad67a6] (diff)

Child: [4bea19] (diff)

Download this file

mimetype.cpp    160 lines (132 with data), 4.0 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#ifndef lint
static char rcsid[] = "@(#$Id: mimetype.cpp,v 1.12 2005-11-21 17:18:58 dockes Exp $ (C) 2004 J.F.Dockes";
#endif
#ifndef TEST_MIMETYPE
#include <ctype.h>
#include <string>
#include <list>
using std::string;
using std::list;
#include "mimetype.h"
#include "debuglog.h"
#include "execmd.h"
#include "rclconfig.h"
#include "smallut.h"
#include "idfile.h"
// Solaris8's 'file' command doesnt understand -i
#ifndef sun
#define USE_SYSTEM_FILE_COMMAND
#endif
/// Identification of file from contents. This is called for files with
/// unrecognized extensions (none, or not known either for indexing or
/// stop list)
///
/// The system 'file' utility is not that great for us. For exemple it
/// will mistake mail folders for simple text files if there is no
/// 'Received' header, which would be the case, for exemple in a 'Sent'
/// folder. Also "file -i" does not exist on all systems, and it's
/// quite costly.
/// So we first call the internal file identifier, which currently
/// only knows about mail, but in which we can add the more
/// current/interesting file types.
/// As a last resort we execute 'file'
static string mimetypefromdata(const string &fn, bool usfc)
{
string mime;
// In any case first try the internal identifier
mime = idFile(fn.c_str());
#ifdef USE_SYSTEM_FILE_COMMAND
if (usfc && mime == "") {
// Last resort: use "file -i"
list<string> args;
args.push_back("-i");
args.push_back(fn);
ExecCmd ex;
string result;
string cmd = "file";
int status = ex.doexec(cmd, args, 0, &result);
if (status) {
LOGERR(("mimetypefromdata: doexec: status 0x%x\n", status));
return "";
}
// LOGDEB(("mimetypefromdata: %s [%s]\n", result.c_str(), fn.c_str()));
// The result of 'file' execution begins with the file name
// which may contain spaces. We happen to know its size, so
// strip it:
result = result.substr(fn.size());
// Now looks like ": text/plain; charset=us-ascii"
// Split it, and take second field
list<string> res;
ConfTree::stringToStrings(result, res);
if (res.size() <= 1)
return "";
list<string>::iterator it = res.begin();
it++;
mime = *it;
// Remove possible punctuation at the end
if (mime.length() > 0 && !isalpha(mime[mime.length() - 1]))
mime.erase(mime.length() -1);
}
#endif
return mime;
}
/// Guess mime type, first from suffix, then from file data. We also
/// have a list of suffixes that we don't touch at all (ie: .jpg,
/// etc...)
string mimetype(const string &fn, RclConfig *cfg, bool usfc)
{
if (cfg == 0)
return "";
list<string> stoplist;
cfg->getStopSuffixes(stoplist);
if (!stoplist.empty()) {
for (list<string>::const_iterator it = stoplist.begin();
it != stoplist.end(); it++) {
if (it->length() > fn.length())
continue;
if (!stringicmp(fn.substr(fn.length() - it->length(),
string::npos), *it)) {
LOGDEB(("mimetype: fn %s in stoplist (%s)\n", fn.c_str(),
it->c_str()));
return "";
}
}
}
// Look for suffix in mimetype map
string::size_type dot = fn.find_last_of(".");
string suff;
if (dot != string::npos) {
suff = fn.substr(dot);
for (unsigned int i = 0; i < suff.length(); i++)
suff[i] = tolower(suff[i]);
string mtype = cfg->getMimeTypeFromSuffix(suff);
if (!mtype.empty())
return mtype;
}
return mimetypefromdata(fn, usfc);
}
#else // TEST->
#include <iostream>
#include "debuglog.h"
#include "rclconfig.h"
#include "rclinit.h"
#include "mimetype.h"
using namespace std;
int main(int argc, const char **argv)
{
string reason;
RclConfig *config = recollinit(0, 0, reason);
if (config == 0 || !config->ok()) {
string str = "Configuration problem: ";
str += reason;
fprintf(stderr, "%s\n", str.c_str());
exit(1);
}
while (--argc > 0) {
string filename = *++argv;
cout << filename << " -> " <<
mimetype(filename, config, true) << endl;
}
return 0;
}
#endif // TEST