]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/mimecmn.cpp
typo fix
[wxWidgets.git] / src / common / mimecmn.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/mimecmn.cpp
3// Purpose: classes and functions to manage MIME types
4// Author: Vadim Zeitlin
5// Modified by:
6// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32
7// Created: 23.09.98
8// RCS-ID: $Id$
9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10// Licence: wxWindows licence (part of wxExtra library)
11/////////////////////////////////////////////////////////////////////////////
12
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
21// for compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
28#if wxUSE_MIMETYPE
29
30#include "wx/mimetype.h"
31
32#ifndef WX_PRECOMP
33 #include "wx/dynarray.h"
34 #include "wx/string.h"
35 #include "wx/intl.h"
36 #include "wx/log.h"
37 #include "wx/module.h"
38 #include "wx/crt.h"
39#endif //WX_PRECOMP
40
41#include "wx/file.h"
42#include "wx/iconloc.h"
43#include "wx/confbase.h"
44
45// other standard headers
46#include <ctype.h>
47
48// implementation classes:
49#if defined(__WXMSW__)
50 #include "wx/msw/mimetype.h"
51#elif defined(__WXMAC__)
52 #include "wx/mac/mimetype.h"
53#elif defined(__WXPM__) || defined (__EMX__)
54 #include "wx/os2/mimetype.h"
55 #undef __UNIX__
56#elif defined(__DOS__)
57 #include "wx/msdos/mimetype.h"
58#else // Unix
59 #include "wx/unix/mimetype.h"
60#endif
61
62// ============================================================================
63// common classes
64// ============================================================================
65
66// ----------------------------------------------------------------------------
67// wxMimeTypeCommands
68// ----------------------------------------------------------------------------
69
70void
71wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd)
72{
73 int n = m_verbs.Index(verb, false /* ignore case */);
74 if ( n == wxNOT_FOUND )
75 {
76 m_verbs.Add(verb);
77 m_commands.Add(cmd);
78 }
79 else
80 {
81 m_commands[n] = cmd;
82 }
83}
84
85wxString
86wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const
87{
88 wxString s;
89
90 int n = m_verbs.Index(verb);
91 if ( n != wxNOT_FOUND )
92 {
93 s = m_commands[(size_t)n];
94 if ( idx )
95 *idx = n;
96 }
97 else if ( idx )
98 {
99 // different from any valid index
100 *idx = (size_t)-1;
101 }
102
103 return s;
104}
105
106wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const
107{
108 return m_verbs[n] + wxT('=') + m_commands[n];
109}
110
111// ----------------------------------------------------------------------------
112// wxFileTypeInfo
113// ----------------------------------------------------------------------------
114
115void wxFileTypeInfo::DoVarArgInit(const wxString& mimeType,
116 const wxString& openCmd,
117 const wxString& printCmd,
118 const wxString& desc,
119 va_list argptr)
120{
121 m_mimeType = mimeType;
122 m_openCmd = openCmd;
123 m_printCmd = printCmd;
124 m_desc = desc;
125
126 for ( ;; )
127 {
128 // icc gives this warning in its own va_arg() macro, argh
129#ifdef __INTELC__
130 #pragma warning(push)
131 #pragma warning(disable: 1684)
132#endif
133
134 wxArgNormalizedString ext(WX_VA_ARG_STRING(argptr));
135
136#ifdef __INTELC__
137 #pragma warning(pop)
138#endif
139 if ( !ext )
140 {
141 // NULL terminates the list
142 break;
143 }
144
145 m_exts.Add(ext.GetString());
146 }
147}
148
149// NB: DoVarArgInit uses WX_VA_ARG_STRING macro to extract the string and this
150// macro interprets the argument as char* or wchar_t* depending on build
151// (and in UTF8 build, on the current locale). Because only one of the
152// vararg forms below is called and the decision about which one gets
153// called depends on the same conditions WX_VA_ARG_STRING uses, we can
154// implement both of them in the exact same way:
155
156#if !wxUSE_UTF8_LOCALE_ONLY
157void wxFileTypeInfo::VarArgInitWchar(const wxChar *mimeType,
158 const wxChar *openCmd,
159 const wxChar *printCmd,
160 const wxChar *desc,
161 ...)
162{
163 va_list argptr;
164 va_start(argptr, desc);
165
166 DoVarArgInit(mimeType, openCmd, printCmd, desc, argptr);
167
168 va_end(argptr);
169}
170#endif // !wxUSE_UTF8_LOCALE_ONLY
171
172#if wxUSE_UNICODE_UTF8
173void wxFileTypeInfo::VarArgInitUtf8(const char *mimeType,
174 const char *openCmd,
175 const char *printCmd,
176 const char *desc,
177 ...)
178{
179 va_list argptr;
180 va_start(argptr, desc);
181
182 DoVarArgInit(mimeType, openCmd, printCmd, desc, argptr);
183
184 va_end(argptr);
185}
186#endif // wxUSE_UNICODE_UTF8
187
188
189wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray)
190{
191 m_mimeType = sArray [0u];
192 m_openCmd = sArray [1u];
193 m_printCmd = sArray [2u];
194 m_desc = sArray [3u];
195
196 size_t count = sArray.GetCount();
197 for ( size_t i = 4; i < count; i++ )
198 {
199 m_exts.Add(sArray[i]);
200 }
201}
202
203#include "wx/arrimpl.cpp"
204WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo)
205
206// ============================================================================
207// implementation of the wrapper classes
208// ============================================================================
209
210// ----------------------------------------------------------------------------
211// wxFileType
212// ----------------------------------------------------------------------------
213
214/* static */
215wxString wxFileType::ExpandCommand(const wxString& command,
216 const wxFileType::MessageParameters& params)
217{
218 bool hasFilename = false;
219
220 wxString str;
221 for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) {
222 if ( *pc == wxT('%') ) {
223 switch ( *++pc ) {
224 case wxT('s'):
225 // '%s' expands into file name (quoted because it might
226 // contain spaces) - except if there are already quotes
227 // there because otherwise some programs may get confused
228 // by double double quotes
229#if 0
230 if ( *(pc - 2) == wxT('"') )
231 str << params.GetFileName();
232 else
233 str << wxT('"') << params.GetFileName() << wxT('"');
234#endif
235 str << params.GetFileName();
236 hasFilename = true;
237 break;
238
239 case wxT('t'):
240 // '%t' expands into MIME type (quote it too just to be
241 // consistent)
242 str << wxT('\'') << params.GetMimeType() << wxT('\'');
243 break;
244
245 case wxT('{'):
246 {
247 const wxChar *pEnd = wxStrchr(pc, wxT('}'));
248 if ( pEnd == NULL ) {
249 wxString mimetype;
250 wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
251 params.GetMimeType().c_str());
252 str << wxT("%{");
253 }
254 else {
255 wxString param(pc + 1, pEnd - pc - 1);
256 str << wxT('\'') << params.GetParamValue(param) << wxT('\'');
257 pc = pEnd;
258 }
259 }
260 break;
261
262 case wxT('n'):
263 case wxT('F'):
264 // TODO %n is the number of parts, %F is an array containing
265 // the names of temp files these parts were written to
266 // and their mime types.
267 break;
268
269 default:
270 wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
271 *pc, command.c_str());
272 str << *pc;
273 }
274 }
275 else {
276 str << *pc;
277 }
278 }
279
280 // metamail(1) man page states that if the mailcap entry doesn't have '%s'
281 // the program will accept the data on stdin so normally we should append
282 // "< %s" to the end of the command in such case, but not all commands
283 // behave like this, in particular a common test is 'test -n "$DISPLAY"'
284 // and appending "< %s" to this command makes the test fail... I don't
285 // know of the correct solution, try to guess what we have to do.
286
287 // test now carried out on reading file so test should never get here
288 if ( !hasFilename && !str.empty()
289#ifdef __UNIX__
290 && !str.StartsWith(_T("test "))
291#endif // Unix
292 ) {
293 str << wxT(" < '") << params.GetFileName() << wxT('\'');
294 }
295
296 return str;
297}
298
299wxFileType::wxFileType(const wxFileTypeInfo& info)
300{
301 m_info = &info;
302 m_impl = NULL;
303}
304
305wxFileType::wxFileType()
306{
307 m_info = NULL;
308 m_impl = new wxFileTypeImpl;
309}
310
311wxFileType::~wxFileType()
312{
313 if ( m_impl )
314 delete m_impl;
315}
316
317bool wxFileType::GetExtensions(wxArrayString& extensions)
318{
319 if ( m_info )
320 {
321 extensions = m_info->GetExtensions();
322 return true;
323 }
324
325 return m_impl->GetExtensions(extensions);
326}
327
328bool wxFileType::GetMimeType(wxString *mimeType) const
329{
330 wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") );
331
332 if ( m_info )
333 {
334 *mimeType = m_info->GetMimeType();
335
336 return true;
337 }
338
339 return m_impl->GetMimeType(mimeType);
340}
341
342bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const
343{
344 if ( m_info )
345 {
346 mimeTypes.Clear();
347 mimeTypes.Add(m_info->GetMimeType());
348
349 return true;
350 }
351
352 return m_impl->GetMimeTypes(mimeTypes);
353}
354
355bool wxFileType::GetIcon(wxIconLocation *iconLoc) const
356{
357 if ( m_info )
358 {
359 if ( iconLoc )
360 {
361 iconLoc->SetFileName(m_info->GetIconFile());
362#ifdef __WXMSW__
363 iconLoc->SetIndex(m_info->GetIconIndex());
364#endif // __WXMSW__
365 }
366
367 return true;
368 }
369
370 return m_impl->GetIcon(iconLoc);
371}
372
373bool
374wxFileType::GetIcon(wxIconLocation *iconloc,
375 const MessageParameters& params) const
376{
377 if ( !GetIcon(iconloc) )
378 {
379 return false;
380 }
381
382 // we may have "%s" in the icon location string, at least under Windows, so
383 // expand this
384 if ( iconloc )
385 {
386 iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params));
387 }
388
389 return true;
390}
391
392bool wxFileType::GetDescription(wxString *desc) const
393{
394 wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") );
395
396 if ( m_info )
397 {
398 *desc = m_info->GetDescription();
399
400 return true;
401 }
402
403 return m_impl->GetDescription(desc);
404}
405
406bool
407wxFileType::GetOpenCommand(wxString *openCmd,
408 const wxFileType::MessageParameters& params) const
409{
410 wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") );
411
412 if ( m_info )
413 {
414 *openCmd = ExpandCommand(m_info->GetOpenCommand(), params);
415
416 return true;
417 }
418
419 return m_impl->GetOpenCommand(openCmd, params);
420}
421
422wxString wxFileType::GetOpenCommand(const wxString& filename) const
423{
424 wxString cmd;
425 if ( !GetOpenCommand(&cmd, filename) )
426 {
427 // return empty string to indicate an error
428 cmd.clear();
429 }
430
431 return cmd;
432}
433
434bool
435wxFileType::GetPrintCommand(wxString *printCmd,
436 const wxFileType::MessageParameters& params) const
437{
438 wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") );
439
440 if ( m_info )
441 {
442 *printCmd = ExpandCommand(m_info->GetPrintCommand(), params);
443
444 return true;
445 }
446
447 return m_impl->GetPrintCommand(printCmd, params);
448}
449
450
451size_t wxFileType::GetAllCommands(wxArrayString *verbs,
452 wxArrayString *commands,
453 const wxFileType::MessageParameters& params) const
454{
455 if ( verbs )
456 verbs->Clear();
457 if ( commands )
458 commands->Clear();
459
460#if defined (__WXMSW__) || defined(__UNIX__)
461 return m_impl->GetAllCommands(verbs, commands, params);
462#else // !__WXMSW__ || Unix
463 // we don't know how to retrieve all commands, so just try the 2 we know
464 // about
465 size_t count = 0;
466 wxString cmd;
467 if ( GetOpenCommand(&cmd, params) )
468 {
469 if ( verbs )
470 verbs->Add(_T("Open"));
471 if ( commands )
472 commands->Add(cmd);
473 count++;
474 }
475
476 if ( GetPrintCommand(&cmd, params) )
477 {
478 if ( verbs )
479 verbs->Add(_T("Print"));
480 if ( commands )
481 commands->Add(cmd);
482
483 count++;
484 }
485
486 return count;
487#endif // __WXMSW__/| __UNIX__
488}
489
490bool wxFileType::Unassociate()
491{
492#if defined(__WXMSW__)
493 return m_impl->Unassociate();
494#elif defined(__UNIX__)
495 return m_impl->Unassociate(this);
496#else
497 wxFAIL_MSG( _T("not implemented") ); // TODO
498 return false;
499#endif
500}
501
502bool wxFileType::SetCommand(const wxString& cmd,
503 const wxString& verb,
504 bool overwriteprompt)
505{
506#if defined (__WXMSW__) || defined(__UNIX__)
507 return m_impl->SetCommand(cmd, verb, overwriteprompt);
508#else
509 wxUnusedVar(cmd);
510 wxUnusedVar(verb);
511 wxUnusedVar(overwriteprompt);
512 wxFAIL_MSG(_T("not implemented"));
513 return false;
514#endif
515}
516
517bool wxFileType::SetDefaultIcon(const wxString& cmd, int index)
518{
519 wxString sTmp = cmd;
520#ifdef __WXMSW__
521 // VZ: should we do this?
522 // chris elliott : only makes sense in MS windows
523 if ( sTmp.empty() )
524 GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString));
525#endif
526 wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") );
527
528#if defined (__WXMSW__) || defined(__UNIX__)
529 return m_impl->SetDefaultIcon (cmd, index);
530#else
531 wxUnusedVar(index);
532 wxFAIL_MSG(_T("not implemented"));
533 return false;
534#endif
535}
536
537// ----------------------------------------------------------------------------
538// wxMimeTypesManagerFactory
539// ----------------------------------------------------------------------------
540
541wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL;
542
543/* static */
544void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory)
545{
546 delete m_factory;
547
548 m_factory = factory;
549}
550
551/* static */
552wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get()
553{
554 if ( !m_factory )
555 m_factory = new wxMimeTypesManagerFactory;
556
557 return m_factory;
558}
559
560wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl()
561{
562 return new wxMimeTypesManagerImpl;
563}
564
565// ----------------------------------------------------------------------------
566// wxMimeTypesManager
567// ----------------------------------------------------------------------------
568
569void wxMimeTypesManager::EnsureImpl()
570{
571 if ( !m_impl )
572 m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl();
573}
574
575bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
576 const wxString& wildcard)
577{
578 wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND,
579 wxT("first MIME type can't contain wildcards") );
580
581 // all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
582 if ( wildcard.BeforeFirst(wxT('/')).
583 IsSameAs(mimeType.BeforeFirst(wxT('/')), false) )
584 {
585 wxString strSubtype = wildcard.AfterFirst(wxT('/'));
586
587 if ( strSubtype == wxT("*") ||
588 strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) )
589 {
590 // matches (either exactly or it's a wildcard)
591 return true;
592 }
593 }
594
595 return false;
596}
597
598wxMimeTypesManager::wxMimeTypesManager()
599{
600 m_impl = NULL;
601}
602
603wxMimeTypesManager::~wxMimeTypesManager()
604{
605 if ( m_impl )
606 delete m_impl;
607}
608
609bool wxMimeTypesManager::Unassociate(wxFileType *ft)
610{
611 EnsureImpl();
612
613#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
614 return m_impl->Unassociate(ft);
615#else
616 return ft->Unassociate();
617#endif
618}
619
620
621wxFileType *
622wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo)
623{
624 EnsureImpl();
625
626#if defined(__WXMSW__) || defined(__UNIX__)
627 return m_impl->Associate(ftInfo);
628#else // other platforms
629 wxUnusedVar(ftInfo);
630 wxFAIL_MSG( _T("not implemented") ); // TODO
631 return NULL;
632#endif // platforms
633}
634
635wxFileType *
636wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext)
637{
638 EnsureImpl();
639
640 wxString::const_iterator i = ext.begin();
641 const wxString::const_iterator end = ext.end();
642 wxString extWithoutDot;
643 if ( i != end && *i == '.' )
644 extWithoutDot.assign(++i, ext.end());
645 else
646 extWithoutDot = ext;
647
648 wxCHECK_MSG( !ext.empty(), NULL, _T("extension can't be empty") );
649
650 wxFileType *ft = m_impl->GetFileTypeFromExtension(extWithoutDot);
651
652 if ( !ft ) {
653 // check the fallbacks
654 //
655 // TODO linear search is potentially slow, perhaps we should use a
656 // sorted array?
657 size_t count = m_fallbacks.GetCount();
658 for ( size_t n = 0; n < count; n++ ) {
659 if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
660 ft = new wxFileType(m_fallbacks[n]);
661
662 break;
663 }
664 }
665 }
666
667 return ft;
668}
669
670wxFileType *
671wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType)
672{
673 EnsureImpl();
674 wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType);
675
676 if ( !ft ) {
677 // check the fallbacks
678 //
679 // TODO linear search is potentially slow, perhaps we should use a
680 // sorted array?
681 size_t count = m_fallbacks.GetCount();
682 for ( size_t n = 0; n < count; n++ ) {
683 if ( wxMimeTypesManager::IsOfType(mimeType,
684 m_fallbacks[n].GetMimeType()) ) {
685 ft = new wxFileType(m_fallbacks[n]);
686
687 break;
688 }
689 }
690 }
691
692 return ft;
693}
694
695bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback)
696{
697 EnsureImpl();
698 return m_impl->ReadMailcap(filename, fallback);
699}
700
701bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename)
702{
703 EnsureImpl();
704 return m_impl->ReadMimeTypes(filename);
705}
706
707void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
708{
709 EnsureImpl();
710 for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) {
711 AddFallback(*ft);
712 }
713}
714
715size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
716{
717 EnsureImpl();
718 size_t countAll = m_impl->EnumAllFileTypes(mimetypes);
719
720 // add the fallback filetypes
721 size_t count = m_fallbacks.GetCount();
722 for ( size_t n = 0; n < count; n++ ) {
723 if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) {
724 mimetypes.Add(m_fallbacks[n].GetMimeType());
725 countAll++;
726 }
727 }
728
729 return countAll;
730}
731
732void wxMimeTypesManager::Initialize(int mcapStyle,
733 const wxString& sExtraDir)
734{
735#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
736 EnsureImpl();
737
738 m_impl->Initialize(mcapStyle, sExtraDir);
739#else
740 (void)mcapStyle;
741 (void)sExtraDir;
742#endif // Unix
743}
744
745// and this function clears all the data from the manager
746void wxMimeTypesManager::ClearData()
747{
748#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
749 EnsureImpl();
750
751 m_impl->ClearData();
752#endif // Unix
753}
754
755// ----------------------------------------------------------------------------
756// global data and wxMimeTypeCmnModule
757// ----------------------------------------------------------------------------
758
759// private object
760static wxMimeTypesManager gs_mimeTypesManager;
761
762// and public pointer
763wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager;
764
765class wxMimeTypeCmnModule: public wxModule
766{
767public:
768 wxMimeTypeCmnModule() : wxModule() { }
769
770 virtual bool OnInit() { return true; }
771 virtual void OnExit()
772 {
773 wxMimeTypesManagerFactory::Set(NULL);
774
775 if ( gs_mimeTypesManager.m_impl != NULL )
776 {
777 delete gs_mimeTypesManager.m_impl;
778 gs_mimeTypesManager.m_impl = NULL;
779 gs_mimeTypesManager.m_fallbacks.Clear();
780 }
781 }
782
783 DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule)
784};
785
786IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule)
787
788#endif // wxUSE_MIMETYPE