mimetype.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,012 行 · 第 1/5 页
CPP
2,012 行
/////////////////////////////////////////////////////////////////////////////
// Name: unix/mimetype.cpp
// Purpose: classes and functions to manage MIME types
// Author: Vadim Zeitlin
// Modified by:
// Created: 23.09.98
// RCS-ID: $Id: mimetype.cpp,v 1.53.2.3 2006/03/17 15:05:03 RR Exp $
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence (part of wxExtra library)
/////////////////////////////////////////////////////////////////////////////
// known bugs; there may be others!! chris elliott, biol75@york.ac.uk 27 Mar 01
// 1) .mailcap and .mimetypes can be either in a netscape or metamail format
// and entries may get confused during writing (I've tried to fix this; please let me know
// any files that fail)
// 2) KDE and Gnome do not yet fully support international read/write
// 3) Gnome key lines like open.latex."LaTeX this file"=latex %f will have odd results
// 4) writing to files comments out the existing data; I hope this avoids losing
// any data which we could not read, and data which we did not store like test=
// 5) results from reading files with multiple entries (especially matches with type/* )
// may (or may not) work for getXXX commands
// 6) Loading the png icons in Gnome doesn't work for me...
// 7) In Gnome, if keys.mime exists but keys.users does not, there is
// an error message in debug mode, but the file is still written OK
// 8) Deleting entries is only allowed from the user file; sytem wide entries
// will be preserved during unassociate
// 9) KDE does not yet handle multiple actions; Netscape mode never will
/*
TODO: this file is a mess, we need to split it and reformet/review
everything (VZ)
*/
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "mimetype.h"
#endif
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/defs.h"
#endif
#if wxUSE_MIMETYPE && wxUSE_FILE && wxUSE_TEXTFILE
#ifndef WX_PRECOMP
#include "wx/string.h"
#endif //WX_PRECOMP
#include "wx/log.h"
#include "wx/file.h"
#include "wx/intl.h"
#include "wx/dynarray.h"
#include "wx/confbase.h"
#include "wx/ffile.h"
#include "wx/textfile.h"
#include "wx/dir.h"
#include "wx/utils.h"
#include "wx/tokenzr.h"
#include "wx/iconloc.h"
#include "wx/filename.h"
#include "wx/unix/mimetype.h"
// other standard headers
#include <ctype.h>
#ifdef __VMS
/* silence warnings for comparing unsigned int's <0 */
# pragma message disable unscomzer
#endif
// wxMimeTypeCommands stores the verbs defined for the given MIME type with
// their values
class wxMimeTypeCommands
{
public:
wxMimeTypeCommands() { }
wxMimeTypeCommands(const wxArrayString& verbs,
const wxArrayString& commands)
: m_verbs(verbs),
m_commands(commands)
{
}
// add a new verb with the command or replace the old value
void AddOrReplaceVerb(const wxString& verb, const wxString& cmd)
{
int n = m_verbs.Index(verb, false /* ignore case */);
if ( n == wxNOT_FOUND )
{
m_verbs.Add(verb);
m_commands.Add(cmd);
}
else
{
m_commands[n] = cmd;
}
}
void Add(const wxString& s)
{
m_verbs.Add(s.BeforeFirst(_T('=')));
m_commands.Add(s.AfterFirst(_T('=')));
}
// access the commands
size_t GetCount() const { return m_verbs.GetCount(); }
const wxString& GetVerb(size_t n) const { return m_verbs[n]; }
const wxString& GetCmd(size_t n) const { return m_commands[n]; }
bool HasVerb(const wxString& verb) const
{ return m_verbs.Index(verb) != wxNOT_FOUND; }
wxString GetCommandForVerb(const wxString& verb, size_t *idx = NULL) const
{
wxString s;
int n = m_verbs.Index(verb);
if ( n != wxNOT_FOUND )
{
s = m_commands[(size_t)n];
if ( idx )
*idx = n;
}
else if ( idx )
{
// different from any valid index
*idx = (size_t)-1;
}
return s;
}
// get a "verb=command" string
wxString GetVerbCmd(size_t n) const
{
return m_verbs[n] + _T('=') + m_commands[n];
}
private:
wxArrayString m_verbs,
m_commands;
};
// this class extends wxTextFile
//
// VZ: ???
class wxMimeTextFile : public wxTextFile
{
public:
// constructors
wxMimeTextFile () : wxTextFile () {};
wxMimeTextFile (const wxString& strFile) : wxTextFile (strFile) { };
int pIndexOf(const wxString & sSearch, bool bIncludeComments = false, int iStart = 0)
{
size_t i = iStart;
int nResult = wxNOT_FOUND;
if (i>=GetLineCount()) return wxNOT_FOUND;
wxString sTest = sSearch;
sTest.MakeLower();
wxString sLine;
if (bIncludeComments)
{
while ( (i < GetLineCount()) )
{
sLine = GetLine (i);
sLine.MakeLower();
if (sLine.Contains(sTest)) nResult = (int) i;
i++;
}
}
else
{
while ( (i < GetLineCount()) )
{
sLine = GetLine (i);
sLine.MakeLower();
if ( ! sLine.StartsWith(wxT("#")))
{
if (sLine.Contains(sTest)) nResult = (int) i;
}
i++;
}
}
return nResult;
}
bool CommentLine(int nIndex)
{
if (nIndex <0) return false;
if (nIndex >= (int)GetLineCount() ) return false;
GetLine(nIndex) = GetLine(nIndex).Prepend(wxT("#"));
return true;
}
bool CommentLine(const wxString & sTest)
{
int nIndex = pIndexOf(sTest);
if (nIndex <0) return false;
if (nIndex >= (int)GetLineCount() ) return false;
GetLine(nIndex) = GetLine(nIndex).Prepend(wxT("#"));
return true;
}
wxString GetVerb (size_t i)
{
if (i > GetLineCount() ) return wxEmptyString;
wxString sTmp = GetLine(i).BeforeFirst(wxT('='));
return sTmp;
}
wxString GetCmd (size_t i)
{
if (i > GetLineCount() ) return wxEmptyString;
wxString sTmp = GetLine(i).AfterFirst(wxT('='));
return sTmp;
}
};
// in case we're compiling in non-GUI mode
class WXDLLEXPORT wxIcon;
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// MIME code tracing mask
#define TRACE_MIME _T("mime")
// give trace messages about the results of mailcap tests
#define TRACE_MIME_TEST _T("mimetest")
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// there are some fields which we don't understand but for which we don't give
// warnings as we know that they're not important - this function is used to
// test for them
static bool IsKnownUnimportantField(const wxString& field);
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// This class uses both mailcap and mime.types to gather information about file
// types.
//
// The information about mailcap file was extracted from metamail(1) sources
// and documentation and subsequently revised when I found the RFC 1524
// describing it.
//
// Format of mailcap file: spaces are ignored, each line is either a comment
// (starts with '#') or a line of the form <field1>;<field2>;...;<fieldN>.
// A backslash can be used to quote semicolons and newlines (and, in fact,
// anything else including itself).
//
// The first field is always the MIME type in the form of type/subtype (see RFC
// 822) where subtype may be '*' meaning "any". Following metamail, we accept
// "type" which means the same as "type/*", although I'm not sure whether this
// is standard.
//
// The second field is always the command to run. It is subject to
// parameter/filename expansion described below.
//
// All the following fields are optional and may not be present at all. If
// they're present they may appear in any order, although each of them should
// appear only once. The optional fields are the following:
// * notes=xxx is an uninterpreted string which is silently ignored
// * test=xxx is the command to be used to determine whether this mailcap line
// applies to our data or not. The RHS of this field goes through the
// parameter/filename expansion (as the 2nd field) and the resulting string
// is executed. The line applies only if the command succeeds, i.e. returns 0
// exit code.
// * print=xxx is the command to be used to print (and not view) the data of
// this type (parameter/filename expansion is done here too)
// * edit=xxx is the command to open/edit the data of this type
// * needsterminal means that a new interactive console must be created for
// the viewer
// * copiousoutput means that the viewer doesn't interact with the user but
// produces (possibly) a lof of lines of output on stdout (i.e. "cat" is a
// good example), thus it might be a good idea to use some kind of paging
// mechanism.
// * textualnewlines means not to perform CR/LF translation (not honored)
// * compose and composetyped fields are used to determine the program to be
// called to create a new message pert in the specified format (unused).
//
// Parameter/filename expansion:
// * %s is replaced with the (full) file name
// * %t is replaced with MIME type/subtype of the entry
// * for multipart type only %n is replaced with the nnumber of parts and %F is
// replaced by an array of (content-type, temporary file name) pairs for all
// message parts (TODO)
// * %{parameter} is replaced with the value of parameter taken from
// Content-type header line of the message.
//
//
// There are 2 possible formats for mime.types file, one entry per line (used
// for global mime.types and called Mosaic format) and "expanded" format where
// an entry takes multiple lines (used for users mime.types and called
// Netscape format).
//
// For both formats spaces are ignored and lines starting with a '#' are
// comments. Each record has one of two following forms:
// a) for "brief" format:
// <mime type> <space separated list of extensions>
// b) for "expanded" format:
// type=<mime type> BACKSLASH
// desc="<description>" BACKSLASH
// exts="<comma separated list of extensions>"
//
// (where BACKSLASH is a literal '\\' which we can't put here because cpp
// misinterprets it)
//
// We try to autodetect the format of mime.types: if a non-comment line starts
// with "type=" we assume the second format, otherwise the first one.
// there may be more than one entry for one and the same mime type, to
// choose the right one we have to run the command specified in the test
// field on our data.
// ----------------------------------------------------------------------------
// wxGNOME
// ----------------------------------------------------------------------------
// GNOME stores the info we're interested in in several locations:
// 1. xxx.keys files under /usr/share/mime-info
// 2. xxx.keys files under ~/.gnome/mime-info
//
// The format of xxx.keys file is the following:
//
// mimetype/subtype:
// field=value
//
// with blank lines separating the entries and indented lines starting with
// TABs. We're interested in the field icon-filename whose value is the path
// containing the icon.
//
// Update (Chris Elliott): apparently there may be an optional "[lang]" prefix
// just before the field name.
void wxMimeTypesManagerImpl::LoadGnomeDataFromKeyFile(const wxString& filename,
const wxArrayString& dirs)
{
wxTextFile textfile(filename);
#if defined(__WXGTK20__) && wxUSE_UNICODE
if ( !textfile.Open( wxConvUTF8) )
#else
if ( !textfile.Open() )
#endif
return;
wxLogTrace(TRACE_MIME, wxT("--- Opened Gnome file %s ---"),
filename.c_str());
// values for the entry being parsed
wxString curMimeType, curIconFile;
wxMimeTypeCommands * entry = new wxMimeTypeCommands;
wxArrayString search_dirs = dirs;
wxArrayString strExtensions;
wxString strDesc;
const wxChar *pc;
size_t nLineCount = textfile.GetLineCount();
size_t nLine = 0;
while ( nLine < nLineCount )
{
pc = textfile[nLine].c_str();
if ( *pc != wxT('#') )
{
wxLogTrace(TRACE_MIME, wxT("--- Reading from Gnome file %s '%s' ---"),
filename.c_str(), pc);
// trim trailing space and tab
while ((*pc == wxT(' ')) || (*pc == wxT('\t')))
pc++;
wxString sTmp(pc);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?