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 + -
显示快捷键?