X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/be0a33fbc07d9ddba2d1167d69d190e4ef64d825..f1d93f0beeec9d88f8a225aa35a9ccc163dcdb15:/src/unix/mimetype.cpp diff --git a/src/unix/mimetype.cpp b/src/unix/mimetype.cpp index 95d459d3bb..1b8cf25097 100644 --- a/src/unix/mimetype.cpp +++ b/src/unix/mimetype.cpp @@ -9,8 +9,16 @@ // Licence: wxWindows license (part of wxExtra library) ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "mimetype.h" +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "mimetype.h" #endif // for compilers that support precompilation, includes "wx.h". @@ -24,7 +32,7 @@ #include "wx/defs.h" #endif -#if (wxUSE_FILE && wxUSE_TEXTFILE) || defined(__WXMSW__) +#if wxUSE_FILE && wxUSE_TEXTFILE #ifndef WX_PRECOMP #include "wx/string.h" @@ -54,6 +62,22 @@ // in case we're compiling in non-GUI mode class WXDLLEXPORT wxIcon; +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// MIME code tracing mask +#define TRACE_MIME _T("mime") + +// ---------------------------------------------------------------------------- +// 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 // ---------------------------------------------------------------------------- @@ -138,6 +162,11 @@ public: { m_next = NULL; } + + ~MailCapEntry() + { + if (m_next) delete m_next; + } // accessors const wxString& GetOpenCmd() const { return m_openCmd; } @@ -208,13 +237,16 @@ class wxGNOMEIconHandler : public wxMimeTypeIconHandler { public: virtual bool GetIcon(const wxString& mimetype, wxIcon *icon); - virtual void GetMimeInfoRecords(wxMimeTypesManagerImpl *manager) {} + virtual void GetMimeInfoRecords(wxMimeTypesManagerImpl *manager); private: void Init(); void LoadIconsFromKeyFile(const wxString& filename); void LoadKeyFilesFromDir(const wxString& dirbase); + void LoadMimeTypesFromMimeFile(const wxString& filename, wxMimeTypesManagerImpl *manager); + void LoadMimeFilesFromDir(const wxString& dirbase, wxMimeTypesManagerImpl *manager); + static bool m_inited; static wxSortedArrayString ms_mimetypes; @@ -375,21 +407,116 @@ void wxGNOMEIconHandler::LoadIconsFromKeyFile(const wxString& filename) { curMimeType += *pc++; } + } + } +} + +void wxGNOMEIconHandler::LoadKeyFilesFromDir(const wxString& dirbase) +{ + wxASSERT_MSG( !!dirbase && !wxEndsWithPathSeparator(dirbase), + _T("base directory shouldn't end with a slash") ); + + wxString dirname = dirbase; + dirname << _T("/mime-info"); + + if ( !wxDir::Exists(dirname) ) + return; + + wxDir dir(dirname); + if ( !dir.IsOpened() ) + return; + + // we will concatenate it with filename to get the full path below + dirname += _T('/'); + + wxString filename; + bool cont = dir.GetFirst(&filename, _T("*.keys"), wxDIR_FILES); + while ( cont ) + { + LoadIconsFromKeyFile(dirname + filename); + + cont = dir.GetNext(&filename); + } +} + + +void wxGNOMEIconHandler::LoadMimeTypesFromMimeFile(const wxString& filename, wxMimeTypesManagerImpl *manager) +{ + wxTextFile textfile(filename); + if ( !textfile.Open() ) + return; + + // values for the entry being parsed + wxString curMimeType, curExtList; + + const wxChar *pc; + size_t nLineCount = textfile.GetLineCount(); + for ( size_t nLine = 0; ; nLine++ ) + { + if ( nLine < nLineCount ) + { + pc = textfile[nLine].c_str(); + if ( *pc == _T('#') ) + { + // skip comments + continue; + } + } + else + { + // so that we will fall into the "if" below + pc = NULL; + } - if ( !*pc ) + if ( !pc || !*pc ) + { + // end of the entry + if ( !!curMimeType && !!curExtList ) { - // we reached the end of line without finding the colon, - // something is wrong - ignore this line completely - wxLogDebug(_T("Unreckognized line %d in file '%s' ignored"), - nLine + 1, filename.c_str()); + manager -> AddMimeTypeInfo(curMimeType, curExtList, wxEmptyString); + } + if ( !pc ) + { + // the end - this can only happen if nLine == nLineCount break; } + + curExtList.Empty(); + + continue; + } + + // what do we have here? + if ( *pc == _T('\t') ) + { + // this is a field=value ling + pc++; // skip leading TAB + + static const int lenField = 4; // strlen("ext:") + if ( wxStrncmp(pc, _T("ext:"), lenField) == 0 ) + { + // skip ' ' which follows and take everything left until the end + // of line + curExtList = pc + lenField + 1; + } + //else: some other field, we don't care + } + else + { + // this is the start of the new section + curMimeType.Empty(); + + while ( *pc != _T(':') && *pc != _T('\0') ) + { + curMimeType += *pc++; + } } } } -void wxGNOMEIconHandler::LoadKeyFilesFromDir(const wxString& dirbase) + +void wxGNOMEIconHandler::LoadMimeFilesFromDir(const wxString& dirbase, wxMimeTypesManagerImpl *manager) { wxASSERT_MSG( !!dirbase && !wxEndsWithPathSeparator(dirbase), _T("base directory shouldn't end with a slash") ); @@ -408,15 +535,16 @@ void wxGNOMEIconHandler::LoadKeyFilesFromDir(const wxString& dirbase) dirname += _T('/'); wxString filename; - bool cont = dir.GetFirst(&filename, _T("*.keys"), wxDIR_FILES); + bool cont = dir.GetFirst(&filename, _T("*.mime"), wxDIR_FILES); while ( cont ) { - LoadIconsFromKeyFile(dirname + filename); + LoadMimeTypesFromMimeFile(dirname + filename, manager); cont = dir.GetNext(&filename); } } + void wxGNOMEIconHandler::Init() { wxArrayString dirs; @@ -437,7 +565,38 @@ void wxGNOMEIconHandler::Init() m_inited = TRUE; } -bool wxGNOMEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon) + +void wxGNOMEIconHandler::GetMimeInfoRecords(wxMimeTypesManagerImpl *manager) +{ + if ( !m_inited ) + { + Init(); + } + + wxArrayString dirs; + dirs.Add(_T("/usr/share")); + dirs.Add(_T("/usr/local/share")); + + wxString gnomedir; + wxGetHomeDir( &gnomedir ); + gnomedir += _T("/.gnome"); + dirs.Add( gnomedir ); + + size_t nDirs = dirs.GetCount(); + for ( size_t nDir = 0; nDir < nDirs; nDir++ ) + { + LoadMimeFilesFromDir(dirs[nDir], manager); + } +} + +#if wxUSE_GUI + #define WXUNUSED_UNLESS_GUI(p) p +#else + #define WXUNUSED_UNLESS_GUI(p) +#endif + +bool wxGNOMEIconHandler::GetIcon(const wxString& mimetype, + wxIcon * WXUNUSED_UNLESS_GUI(icon)) { if ( !m_inited ) { @@ -457,8 +616,11 @@ bool wxGNOMEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon) icn = wxIcon(iconname); else icn = wxIcon(iconname, wxBITMAP_TYPE_ANY); - if (icn.Ok()) *icon = icn; - else return FALSE; + if ( !icn.Ok() ) + return FALSE; + + if ( icon ) + *icon = icn; #else // helpful for testing in console mode wxLogDebug(_T("Found GNOME icon for '%s': '%s'\n"), @@ -665,6 +827,7 @@ void wxKDEIconHandler::Init() dirs.Add(_T("/usr/share")); dirs.Add(_T("/opt/kde/share")); icondirs.Add(_T("/usr/share/icons/")); + icondirs.Add(_T("/usr/X11R6/share/icons/")); // Debian/Corel linux icondirs.Add(_T("/opt/kde/share/icons/")); } @@ -677,7 +840,8 @@ void wxKDEIconHandler::Init() m_inited = TRUE; } -bool wxKDEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon) +bool wxKDEIconHandler::GetIcon(const wxString& mimetype, + wxIcon * WXUNUSED_UNLESS_GUI(icon)) { if ( !m_inited ) { @@ -697,8 +861,12 @@ bool wxKDEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon) icn = wxIcon(iconname); else icn = wxIcon(iconname, wxBITMAP_TYPE_ANY); - if (icn.Ok()) *icon = icn; - else return FALSE; + + if ( !icn.Ok() ) + return FALSE; + + if ( icon ) + *icon = icn; #else // helpful for testing in console mode wxLogDebug(_T("Found KDE icon for '%s': '%s'\n"), @@ -727,20 +895,26 @@ MailCapEntry * wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const { wxString command; - MailCapEntry *entry = m_manager->m_aEntries[m_index]; + MailCapEntry *entry = m_manager->m_aEntries[m_index[0]]; while ( entry != NULL ) { // notice that an empty command would always succeed (it's ok) command = wxFileType::ExpandCommand(entry->GetTestCmd(), params); - if ( command.IsEmpty() || (wxSystem(command) == 0) ) { - // ok, passed - wxLogTrace(wxT("Test '%s' for mime type '%s' succeeded."), - command.c_str(), params.GetMimeType().c_str()); - break; - } - else { - wxLogTrace(wxT("Test '%s' for mime type '%s' failed."), - command.c_str(), params.GetMimeType().c_str()); + // suppress the command output + if ( !command.IsEmpty() ) + { + if ( wxSystem(command) == 0 ) { + // ok, passed + wxLogTrace(TRACE_MIME, + wxT("Test '%s' for mime type '%s' succeeded."), + command.c_str(), params.GetMimeType().c_str()); + break; + } + else { + wxLogTrace(TRACE_MIME, + wxT("Test '%s' for mime type '%s' failed."), + command.c_str(), params.GetMimeType().c_str()); + } } entry = entry->GetNext(); @@ -751,20 +925,35 @@ wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const bool wxFileTypeImpl::GetIcon(wxIcon *icon) const { - wxString mimetype; - (void)GetMimeType(&mimetype); + wxArrayString mimetypes; + GetMimeTypes(mimetypes); ArrayIconHandlers& handlers = m_manager->GetIconHandlers(); size_t count = handlers.GetCount(); + size_t counttypes = mimetypes.GetCount(); for ( size_t n = 0; n < count; n++ ) { - if ( handlers[n]->GetIcon(mimetype, icon) ) - return TRUE; + for ( size_t n2 = 0; n2 < counttypes; n2++ ) + { + if ( handlers[n]->GetIcon(mimetypes[n2], icon) ) + return TRUE; + } } return FALSE; } + +bool +wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const +{ + mimeTypes.Clear(); + for (size_t i = 0; i < m_index.GetCount(); i++) + mimeTypes.Add(m_manager->m_aTypes[m_index[i]]); + return TRUE; +} + + bool wxFileTypeImpl::GetExpandedCommand(wxString *expandedCmd, const wxFileType::MessageParameters& params, @@ -788,7 +977,7 @@ wxFileTypeImpl::GetExpandedCommand(wxString *expandedCmd, bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) { - wxString strExtensions = m_manager->GetExtension(m_index); + wxString strExtensions = m_manager->GetExtension(m_index[0]); extensions.Empty(); // one extension in the space or comma delimitid list @@ -829,8 +1018,8 @@ ArrayIconHandlers& wxMimeTypesManagerImpl::GetIconHandlers() { if ( ms_iconHandlers.GetCount() == 0 ) { - ms_iconHandlers.Add(&gs_iconHandlerKDE); ms_iconHandlers.Add(&gs_iconHandlerGNOME); + ms_iconHandlers.Add(&gs_iconHandlerKDE); } return ms_iconHandlers; @@ -839,12 +1028,6 @@ ArrayIconHandlers& wxMimeTypesManagerImpl::GetIconHandlers() // read system and user mailcaps (TODO implement mime.types support) wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() { - // read KDE/GNOME tables - ArrayIconHandlers& handlers = GetIconHandlers(); - size_t count = handlers.GetCount(); - for ( size_t hn = 0; hn < count; hn++ ) - handlers[hn]->GetMimeInfoRecords(this); - // directories where we look for mailcap and mime.types by default // (taken from metamail(1) sources) static const wxChar *aStandardLocations[] = @@ -885,11 +1068,26 @@ wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() if ( wxFile::Exists(strUserMimeTypes) ) { ReadMimeTypes(strUserMimeTypes); } + + // read KDE/GNOME tables + ArrayIconHandlers& handlers = GetIconHandlers(); + size_t count = handlers.GetCount(); + for ( size_t hn = 0; hn < count; hn++ ) + handlers[hn]->GetMimeInfoRecords(this); +} + + +wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl() +{ + size_t cnt = m_aEntries.GetCount(); + for (size_t i = 0; i < cnt; i++) delete m_aEntries[i]; } + wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) { + wxFileType *fileType = NULL; size_t count = m_aExtensions.GetCount(); for ( size_t n = 0; n < count; n++ ) { wxString extensions = m_aExtensions[n]; @@ -900,16 +1098,14 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) // consider extensions as not being case-sensitive if ( field.IsSameAs(ext, FALSE /* no case */) ) { // found - wxFileType *fileType = new wxFileType; + if (fileType == NULL) fileType = new wxFileType; fileType->m_impl->Init(this, n); - - return fileType; + // adds this mime type to _list_ of mime types with this extension } } } - // not found - return NULL; + return fileType; } wxFileType * @@ -1023,7 +1219,8 @@ void wxMimeTypesManagerImpl::AddMailcapInfo(const wxString& strType, bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) { - wxLogTrace(wxT("--- Parsing mime.types file '%s' ---"), strFileName.c_str()); + wxLogTrace(TRACE_MIME, wxT("--- Parsing mime.types file '%s' ---"), + strFileName.c_str()); wxTextFile file(strFileName); if ( !file.Open() ) @@ -1098,8 +1295,9 @@ bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) } } else { - // unquoted string ends at the first space - for ( pEnd = pc; !wxIsspace(*pEnd); pEnd++ ) + // unquoted string ends at the first space or at the end of + // line + for ( pEnd = pc; *pEnd && !wxIsspace(*pEnd); pEnd++ ) ; } @@ -1178,7 +1376,8 @@ bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName, bool fallback) { - wxLogTrace(wxT("--- Parsing mailcap file '%s' ---"), strFileName.c_str()); + wxLogTrace(TRACE_MIME, wxT("--- Parsing mailcap file '%s' ---"), + strFileName.c_str()); wxTextFile file(strFileName); if ( !file.Open() ) @@ -1328,10 +1527,7 @@ bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName, if ( !ok ) { - // we don't understand this field, but - // Netscape stores info in it, so don't warn - // about it - if ( curField.Left(16u) != "x-mozilla-flags=" ) + if ( !IsKnownUnimportantField(curField) ) { // don't flood the user with error // messages if we don't understand @@ -1471,6 +1667,29 @@ size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes) return mimetypes.GetCount(); } +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static bool IsKnownUnimportantField(const wxString& fieldAll) +{ + static const wxChar *knownFields[] = + { + _T("x-mozilla-flags"), + _T("nametemplate"), + _T("textualnewlines"), + }; + + wxString field = fieldAll.BeforeFirst(_T('=')); + for ( size_t n = 0; n < WXSIZEOF(knownFields); n++ ) + { + if ( field.CmpNoCase(knownFields[n]) == 0 ) + return TRUE; + } + + return FALSE; +} + #endif // wxUSE_FILE && wxUSE_TEXTFILE