1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/mimecmn.cpp
3 // Purpose: classes and functions to manage MIME types
4 // Author: Vadim Zeitlin
6 // Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32
9 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows licence (part of wxExtra library)
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // for compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
30 #include "wx/mimetype.h"
33 #include "wx/dynarray.h"
34 #include "wx/string.h"
37 #include "wx/module.h"
41 #include "wx/iconloc.h"
42 #include "wx/confbase.h"
44 // other standard headers
47 // implementation classes:
48 #if defined(__WXMSW__)
49 #include "wx/msw/mimetype.h"
50 #elif defined(__WXMAC__)
51 #include "wx/mac/mimetype.h"
52 #elif defined(__WXPM__) || defined (__EMX__)
53 #include "wx/os2/mimetype.h"
55 #elif defined(__DOS__)
56 #include "wx/msdos/mimetype.h"
58 #include "wx/unix/mimetype.h"
61 // ============================================================================
63 // ============================================================================
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
70 wxMimeTypeCommands::AddOrReplaceVerb(const wxString
& verb
, const wxString
& cmd
)
72 int n
= m_verbs
.Index(verb
, false /* ignore case */);
73 if ( n
== wxNOT_FOUND
)
85 wxMimeTypeCommands::GetCommandForVerb(const wxString
& verb
, size_t *idx
) const
89 int n
= m_verbs
.Index(verb
);
90 if ( n
!= wxNOT_FOUND
)
92 s
= m_commands
[(size_t)n
];
98 // different from any valid index
105 wxString
wxMimeTypeCommands::GetVerbCmd(size_t n
) const
107 return m_verbs
[n
] + wxT('=') + m_commands
[n
];
110 // ----------------------------------------------------------------------------
112 // ----------------------------------------------------------------------------
114 wxFileTypeInfo::wxFileTypeInfo(const wxChar
*mimeType
,
115 const wxChar
*openCmd
,
116 const wxChar
*printCmd
,
119 : m_mimeType(mimeType
),
121 m_printCmd(printCmd
),
125 va_start(argptr
, desc
);
129 // icc gives this warning in its own va_arg() macro, argh
131 #pragma warning(push)
132 #pragma warning(disable: 1684)
135 const wxChar
*ext
= va_arg(argptr
, const wxChar
*);
142 // NULL terminates the list
153 wxFileTypeInfo::wxFileTypeInfo(const wxArrayString
& sArray
)
155 m_mimeType
= sArray
[0u];
156 m_openCmd
= sArray
[1u];
157 m_printCmd
= sArray
[2u];
158 m_desc
= sArray
[3u];
160 size_t count
= sArray
.GetCount();
161 for ( size_t i
= 4; i
< count
; i
++ )
163 m_exts
.Add(sArray
[i
]);
167 #include "wx/arrimpl.cpp"
168 WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo
)
170 // ============================================================================
171 // implementation of the wrapper classes
172 // ============================================================================
174 // ----------------------------------------------------------------------------
176 // ----------------------------------------------------------------------------
179 wxString
wxFileType::ExpandCommand(const wxString
& command
,
180 const wxFileType::MessageParameters
& params
)
182 bool hasFilename
= false;
185 for ( const wxChar
*pc
= command
.c_str(); *pc
!= wxT('\0'); pc
++ ) {
186 if ( *pc
== wxT('%') ) {
189 // '%s' expands into file name (quoted because it might
190 // contain spaces) - except if there are already quotes
191 // there because otherwise some programs may get confused
192 // by double double quotes
194 if ( *(pc
- 2) == wxT('"') )
195 str
<< params
.GetFileName();
197 str
<< wxT('"') << params
.GetFileName() << wxT('"');
199 str
<< params
.GetFileName();
204 // '%t' expands into MIME type (quote it too just to be
206 str
<< wxT('\'') << params
.GetMimeType() << wxT('\'');
211 const wxChar
*pEnd
= wxStrchr(pc
, wxT('}'));
212 if ( pEnd
== NULL
) {
214 wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
215 params
.GetMimeType().c_str());
219 wxString
param(pc
+ 1, pEnd
- pc
- 1);
220 str
<< wxT('\'') << params
.GetParamValue(param
) << wxT('\'');
228 // TODO %n is the number of parts, %F is an array containing
229 // the names of temp files these parts were written to
230 // and their mime types.
234 wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
235 *pc
, command
.c_str());
244 // metamail(1) man page states that if the mailcap entry doesn't have '%s'
245 // the program will accept the data on stdin so normally we should append
246 // "< %s" to the end of the command in such case, but not all commands
247 // behave like this, in particular a common test is 'test -n "$DISPLAY"'
248 // and appending "< %s" to this command makes the test fail... I don't
249 // know of the correct solution, try to guess what we have to do.
251 // test now carried out on reading file so test should never get here
252 if ( !hasFilename
&& !str
.empty()
254 && !str
.StartsWith(_T("test "))
257 str
<< wxT(" < '") << params
.GetFileName() << wxT('\'');
263 wxFileType::wxFileType(const wxFileTypeInfo
& info
)
269 wxFileType::wxFileType()
272 m_impl
= new wxFileTypeImpl
;
275 wxFileType::~wxFileType()
281 bool wxFileType::GetExtensions(wxArrayString
& extensions
)
285 extensions
= m_info
->GetExtensions();
289 return m_impl
->GetExtensions(extensions
);
292 bool wxFileType::GetMimeType(wxString
*mimeType
) const
294 wxCHECK_MSG( mimeType
, false, _T("invalid parameter in GetMimeType") );
298 *mimeType
= m_info
->GetMimeType();
303 return m_impl
->GetMimeType(mimeType
);
306 bool wxFileType::GetMimeTypes(wxArrayString
& mimeTypes
) const
311 mimeTypes
.Add(m_info
->GetMimeType());
316 return m_impl
->GetMimeTypes(mimeTypes
);
319 bool wxFileType::GetIcon(wxIconLocation
*iconLoc
) const
325 iconLoc
->SetFileName(m_info
->GetIconFile());
327 iconLoc
->SetIndex(m_info
->GetIconIndex());
334 return m_impl
->GetIcon(iconLoc
);
338 wxFileType::GetIcon(wxIconLocation
*iconloc
,
339 const MessageParameters
& params
) const
341 if ( !GetIcon(iconloc
) )
346 // we may have "%s" in the icon location string, at least under Windows, so
350 iconloc
->SetFileName(ExpandCommand(iconloc
->GetFileName(), params
));
356 bool wxFileType::GetDescription(wxString
*desc
) const
358 wxCHECK_MSG( desc
, false, _T("invalid parameter in GetDescription") );
362 *desc
= m_info
->GetDescription();
367 return m_impl
->GetDescription(desc
);
371 wxFileType::GetOpenCommand(wxString
*openCmd
,
372 const wxFileType::MessageParameters
& params
) const
374 wxCHECK_MSG( openCmd
, false, _T("invalid parameter in GetOpenCommand") );
378 *openCmd
= ExpandCommand(m_info
->GetOpenCommand(), params
);
383 return m_impl
->GetOpenCommand(openCmd
, params
);
386 wxString
wxFileType::GetOpenCommand(const wxString
& filename
) const
389 if ( !GetOpenCommand(&cmd
, filename
) )
391 // return empty string to indicate an error
399 wxFileType::GetPrintCommand(wxString
*printCmd
,
400 const wxFileType::MessageParameters
& params
) const
402 wxCHECK_MSG( printCmd
, false, _T("invalid parameter in GetPrintCommand") );
406 *printCmd
= ExpandCommand(m_info
->GetPrintCommand(), params
);
411 return m_impl
->GetPrintCommand(printCmd
, params
);
415 size_t wxFileType::GetAllCommands(wxArrayString
*verbs
,
416 wxArrayString
*commands
,
417 const wxFileType::MessageParameters
& params
) const
424 #if defined (__WXMSW__) || defined(__UNIX__)
425 return m_impl
->GetAllCommands(verbs
, commands
, params
);
426 #else // !__WXMSW__ || Unix
427 // we don't know how to retrieve all commands, so just try the 2 we know
431 if ( GetOpenCommand(&cmd
, params
) )
434 verbs
->Add(_T("Open"));
440 if ( GetPrintCommand(&cmd
, params
) )
443 verbs
->Add(_T("Print"));
451 #endif // __WXMSW__/| __UNIX__
454 bool wxFileType::Unassociate()
456 #if defined(__WXMSW__)
457 return m_impl
->Unassociate();
458 #elif defined(__UNIX__)
459 return m_impl
->Unassociate(this);
461 wxFAIL_MSG( _T("not implemented") ); // TODO
466 bool wxFileType::SetCommand(const wxString
& cmd
,
467 const wxString
& verb
,
468 bool overwriteprompt
)
470 #if defined (__WXMSW__) || defined(__UNIX__)
471 return m_impl
->SetCommand(cmd
, verb
, overwriteprompt
);
475 wxUnusedVar(overwriteprompt
);
476 wxFAIL_MSG(_T("not implemented"));
481 bool wxFileType::SetDefaultIcon(const wxString
& cmd
, int index
)
485 // VZ: should we do this?
486 // chris elliott : only makes sense in MS windows
488 GetOpenCommand(&sTmp
, wxFileType::MessageParameters(wxEmptyString
, wxEmptyString
));
490 wxCHECK_MSG( !sTmp
.empty(), false, _T("need the icon file") );
492 #if defined (__WXMSW__) || defined(__UNIX__)
493 return m_impl
->SetDefaultIcon (cmd
, index
);
496 wxFAIL_MSG(_T("not implemented"));
501 // ----------------------------------------------------------------------------
502 // wxMimeTypesManagerFactory
503 // ----------------------------------------------------------------------------
505 wxMimeTypesManagerFactory
*wxMimeTypesManagerFactory::m_factory
= NULL
;
508 void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory
*factory
)
516 wxMimeTypesManagerFactory
*wxMimeTypesManagerFactory::Get()
519 m_factory
= new wxMimeTypesManagerFactory
;
524 wxMimeTypesManagerImpl
*wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl()
526 return new wxMimeTypesManagerImpl
;
529 // ----------------------------------------------------------------------------
530 // wxMimeTypesManager
531 // ----------------------------------------------------------------------------
533 void wxMimeTypesManager::EnsureImpl()
536 m_impl
= wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl();
539 bool wxMimeTypesManager::IsOfType(const wxString
& mimeType
,
540 const wxString
& wildcard
)
542 wxASSERT_MSG( mimeType
.Find(wxT('*')) == wxNOT_FOUND
,
543 wxT("first MIME type can't contain wildcards") );
545 // all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
546 if ( wildcard
.BeforeFirst(wxT('/')).
547 IsSameAs(mimeType
.BeforeFirst(wxT('/')), false) )
549 wxString strSubtype
= wildcard
.AfterFirst(wxT('/'));
551 if ( strSubtype
== wxT("*") ||
552 strSubtype
.IsSameAs(mimeType
.AfterFirst(wxT('/')), false) )
554 // matches (either exactly or it's a wildcard)
562 wxMimeTypesManager::wxMimeTypesManager()
567 wxMimeTypesManager::~wxMimeTypesManager()
573 bool wxMimeTypesManager::Unassociate(wxFileType
*ft
)
577 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
578 return m_impl
->Unassociate(ft
);
580 return ft
->Unassociate();
586 wxMimeTypesManager::Associate(const wxFileTypeInfo
& ftInfo
)
590 #if defined(__WXMSW__) || defined(__UNIX__)
591 return m_impl
->Associate(ftInfo
);
592 #else // other platforms
594 wxFAIL_MSG( _T("not implemented") ); // TODO
600 wxMimeTypesManager::GetFileTypeFromExtension(const wxString
& ext
)
603 wxFileType
*ft
= m_impl
->GetFileTypeFromExtension(ext
);
606 // check the fallbacks
608 // TODO linear search is potentially slow, perhaps we should use a
610 size_t count
= m_fallbacks
.GetCount();
611 for ( size_t n
= 0; n
< count
; n
++ ) {
612 if ( m_fallbacks
[n
].GetExtensions().Index(ext
) != wxNOT_FOUND
) {
613 ft
= new wxFileType(m_fallbacks
[n
]);
624 wxMimeTypesManager::GetFileTypeFromMimeType(const wxString
& mimeType
)
627 wxFileType
*ft
= m_impl
->GetFileTypeFromMimeType(mimeType
);
630 // check the fallbacks
632 // TODO linear search is potentially slow, perhaps we should use a
634 size_t count
= m_fallbacks
.GetCount();
635 for ( size_t n
= 0; n
< count
; n
++ ) {
636 if ( wxMimeTypesManager::IsOfType(mimeType
,
637 m_fallbacks
[n
].GetMimeType()) ) {
638 ft
= new wxFileType(m_fallbacks
[n
]);
648 bool wxMimeTypesManager::ReadMailcap(const wxString
& filename
, bool fallback
)
651 return m_impl
->ReadMailcap(filename
, fallback
);
654 bool wxMimeTypesManager::ReadMimeTypes(const wxString
& filename
)
657 return m_impl
->ReadMimeTypes(filename
);
660 void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo
*filetypes
)
663 for ( const wxFileTypeInfo
*ft
= filetypes
; ft
&& ft
->IsValid(); ft
++ ) {
668 size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString
& mimetypes
)
671 size_t countAll
= m_impl
->EnumAllFileTypes(mimetypes
);
673 // add the fallback filetypes
674 size_t count
= m_fallbacks
.GetCount();
675 for ( size_t n
= 0; n
< count
; n
++ ) {
676 if ( mimetypes
.Index(m_fallbacks
[n
].GetMimeType()) == wxNOT_FOUND
) {
677 mimetypes
.Add(m_fallbacks
[n
].GetMimeType());
685 void wxMimeTypesManager::Initialize(int mcapStyle
,
686 const wxString
& sExtraDir
)
688 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
691 m_impl
->Initialize(mcapStyle
, sExtraDir
);
698 // and this function clears all the data from the manager
699 void wxMimeTypesManager::ClearData()
701 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
708 // ----------------------------------------------------------------------------
709 // global data and wxMimeTypeCmnModule
710 // ----------------------------------------------------------------------------
713 static wxMimeTypesManager gs_mimeTypesManager
;
715 // and public pointer
716 wxMimeTypesManager
*wxTheMimeTypesManager
= &gs_mimeTypesManager
;
718 class wxMimeTypeCmnModule
: public wxModule
721 wxMimeTypeCmnModule() : wxModule() { }
723 virtual bool OnInit() { return true; }
724 virtual void OnExit()
726 wxMimeTypesManagerFactory::Set(NULL
);
728 if ( gs_mimeTypesManager
.m_impl
!= NULL
)
730 delete gs_mimeTypesManager
.m_impl
;
731 gs_mimeTypesManager
.m_impl
= NULL
;
732 gs_mimeTypesManager
.m_fallbacks
.Clear();
736 DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule
)
739 IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule
, wxModule
)
741 #endif // wxUSE_MIMETYPE