remove extraneous semicolons (patch 1299687)
[wxWidgets.git] / src / common / mimecmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifndef WX_PRECOMP
31 #include "wx/string.h"
32 #endif //WX_PRECOMP
33
34 #include "wx/module.h"
35 #include "wx/log.h"
36 #include "wx/file.h"
37 #include "wx/iconloc.h"
38 #include "wx/intl.h"
39 #include "wx/dynarray.h"
40 #include "wx/confbase.h"
41
42 #include "wx/mimetype.h"
43
44 // other standard headers
45 #include <ctype.h>
46
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"
54 #undef __UNIX__
55 #elif defined(__DOS__)
56 #include "wx/msdos/mimetype.h"
57 #else // Unix
58 #include "wx/unix/mimetype.h"
59 #endif
60
61 // ============================================================================
62 // common classes
63 // ============================================================================
64
65 // ----------------------------------------------------------------------------
66 // wxFileTypeInfo
67 // ----------------------------------------------------------------------------
68
69 wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType,
70 const wxChar *openCmd,
71 const wxChar *printCmd,
72 const wxChar *desc,
73 ...)
74 : m_mimeType(mimeType),
75 m_openCmd(openCmd),
76 m_printCmd(printCmd),
77 m_desc(desc)
78 {
79 va_list argptr;
80 va_start(argptr, desc);
81
82 for ( ;; )
83 {
84 const wxChar *ext = va_arg(argptr, const wxChar *);
85 if ( !ext )
86 {
87 // NULL terminates the list
88 break;
89 }
90
91 m_exts.Add(ext);
92 }
93
94 va_end(argptr);
95 }
96
97
98 wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray)
99 {
100 m_mimeType = sArray [0u];
101 m_openCmd = sArray [1u];
102 m_printCmd = sArray [2u];
103 m_desc = sArray [3u];
104
105 size_t count = sArray.GetCount();
106 for ( size_t i = 4; i < count; i++ )
107 {
108 m_exts.Add(sArray[i]);
109 }
110 }
111
112 #include "wx/arrimpl.cpp"
113 WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo)
114
115 // ============================================================================
116 // implementation of the wrapper classes
117 // ============================================================================
118
119 // ----------------------------------------------------------------------------
120 // wxFileType
121 // ----------------------------------------------------------------------------
122
123 /* static */
124 wxString wxFileType::ExpandCommand(const wxString& command,
125 const wxFileType::MessageParameters& params)
126 {
127 bool hasFilename = false;
128
129 wxString str;
130 for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) {
131 if ( *pc == wxT('%') ) {
132 switch ( *++pc ) {
133 case wxT('s'):
134 // '%s' expands into file name (quoted because it might
135 // contain spaces) - except if there are already quotes
136 // there because otherwise some programs may get confused
137 // by double double quotes
138 #if 0
139 if ( *(pc - 2) == wxT('"') )
140 str << params.GetFileName();
141 else
142 str << wxT('"') << params.GetFileName() << wxT('"');
143 #endif
144 str << params.GetFileName();
145 hasFilename = true;
146 break;
147
148 case wxT('t'):
149 // '%t' expands into MIME type (quote it too just to be
150 // consistent)
151 str << wxT('\'') << params.GetMimeType() << wxT('\'');
152 break;
153
154 case wxT('{'):
155 {
156 const wxChar *pEnd = wxStrchr(pc, wxT('}'));
157 if ( pEnd == NULL ) {
158 wxString mimetype;
159 wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
160 params.GetMimeType().c_str());
161 str << wxT("%{");
162 }
163 else {
164 wxString param(pc + 1, pEnd - pc - 1);
165 str << wxT('\'') << params.GetParamValue(param) << wxT('\'');
166 pc = pEnd;
167 }
168 }
169 break;
170
171 case wxT('n'):
172 case wxT('F'):
173 // TODO %n is the number of parts, %F is an array containing
174 // the names of temp files these parts were written to
175 // and their mime types.
176 break;
177
178 default:
179 wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
180 *pc, command.c_str());
181 str << *pc;
182 }
183 }
184 else {
185 str << *pc;
186 }
187 }
188
189 // metamail(1) man page states that if the mailcap entry doesn't have '%s'
190 // the program will accept the data on stdin so normally we should append
191 // "< %s" to the end of the command in such case, but not all commands
192 // behave like this, in particular a common test is 'test -n "$DISPLAY"'
193 // and appending "< %s" to this command makes the test fail... I don't
194 // know of the correct solution, try to guess what we have to do.
195
196 // test now carried out on reading file so test should never get here
197 if ( !hasFilename && !str.empty()
198 #ifdef __UNIX__
199 && !str.StartsWith(_T("test "))
200 #endif // Unix
201 ) {
202 str << wxT(" < '") << params.GetFileName() << wxT('\'');
203 }
204
205 return str;
206 }
207
208 wxFileType::wxFileType(const wxFileTypeInfo& info)
209 {
210 m_info = &info;
211 m_impl = NULL;
212 }
213
214 wxFileType::wxFileType()
215 {
216 m_info = NULL;
217 m_impl = new wxFileTypeImpl;
218 }
219
220 wxFileType::~wxFileType()
221 {
222 if ( m_impl )
223 delete m_impl;
224 }
225
226 bool wxFileType::GetExtensions(wxArrayString& extensions)
227 {
228 if ( m_info )
229 {
230 extensions = m_info->GetExtensions();
231 return true;
232 }
233
234 return m_impl->GetExtensions(extensions);
235 }
236
237 bool wxFileType::GetMimeType(wxString *mimeType) const
238 {
239 wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") );
240
241 if ( m_info )
242 {
243 *mimeType = m_info->GetMimeType();
244
245 return true;
246 }
247
248 return m_impl->GetMimeType(mimeType);
249 }
250
251 bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const
252 {
253 if ( m_info )
254 {
255 mimeTypes.Clear();
256 mimeTypes.Add(m_info->GetMimeType());
257
258 return true;
259 }
260
261 return m_impl->GetMimeTypes(mimeTypes);
262 }
263
264 bool wxFileType::GetIcon(wxIconLocation *iconLoc) const
265 {
266 if ( m_info )
267 {
268 if ( iconLoc )
269 {
270 iconLoc->SetFileName(m_info->GetIconFile());
271 #ifdef __WXMSW__
272 iconLoc->SetIndex(m_info->GetIconIndex());
273 #endif // __WXMSW__
274 }
275
276 return true;
277 }
278
279 return m_impl->GetIcon(iconLoc);
280 }
281
282 bool
283 wxFileType::GetIcon(wxIconLocation *iconloc,
284 const MessageParameters& params) const
285 {
286 if ( !GetIcon(iconloc) )
287 {
288 return false;
289 }
290
291 // we may have "%s" in the icon location string, at least under Windows, so
292 // expand this
293 if ( iconloc )
294 {
295 iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params));
296 }
297
298 return true;
299 }
300
301 bool wxFileType::GetDescription(wxString *desc) const
302 {
303 wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") );
304
305 if ( m_info )
306 {
307 *desc = m_info->GetDescription();
308
309 return true;
310 }
311
312 return m_impl->GetDescription(desc);
313 }
314
315 bool
316 wxFileType::GetOpenCommand(wxString *openCmd,
317 const wxFileType::MessageParameters& params) const
318 {
319 wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") );
320
321 if ( m_info )
322 {
323 *openCmd = ExpandCommand(m_info->GetOpenCommand(), params);
324
325 return true;
326 }
327
328 return m_impl->GetOpenCommand(openCmd, params);
329 }
330
331 wxString wxFileType::GetOpenCommand(const wxString& filename) const
332 {
333 wxString cmd;
334 if ( !GetOpenCommand(&cmd, filename) )
335 {
336 // return empty string to indicate an error
337 cmd.clear();
338 }
339
340 return cmd;
341 }
342
343 bool
344 wxFileType::GetPrintCommand(wxString *printCmd,
345 const wxFileType::MessageParameters& params) const
346 {
347 wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") );
348
349 if ( m_info )
350 {
351 *printCmd = ExpandCommand(m_info->GetPrintCommand(), params);
352
353 return true;
354 }
355
356 return m_impl->GetPrintCommand(printCmd, params);
357 }
358
359
360 size_t wxFileType::GetAllCommands(wxArrayString *verbs,
361 wxArrayString *commands,
362 const wxFileType::MessageParameters& params) const
363 {
364 if ( verbs )
365 verbs->Clear();
366 if ( commands )
367 commands->Clear();
368
369 #if defined (__WXMSW__) || defined(__UNIX__)
370 return m_impl->GetAllCommands(verbs, commands, params);
371 #else // !__WXMSW__ || Unix
372 // we don't know how to retrieve all commands, so just try the 2 we know
373 // about
374 size_t count = 0;
375 wxString cmd;
376 if ( GetOpenCommand(&cmd, params) )
377 {
378 if ( verbs )
379 verbs->Add(_T("Open"));
380 if ( commands )
381 commands->Add(cmd);
382 count++;
383 }
384
385 if ( GetPrintCommand(&cmd, params) )
386 {
387 if ( verbs )
388 verbs->Add(_T("Print"));
389 if ( commands )
390 commands->Add(cmd);
391
392 count++;
393 }
394
395 return count;
396 #endif // __WXMSW__/| __UNIX__
397 }
398
399 bool wxFileType::Unassociate()
400 {
401 #if defined(__WXMSW__)
402 return m_impl->Unassociate();
403 #elif defined(__UNIX__)
404 return m_impl->Unassociate(this);
405 #else
406 wxFAIL_MSG( _T("not implemented") ); // TODO
407 return false;
408 #endif
409 }
410
411 bool wxFileType::SetCommand(const wxString& cmd,
412 const wxString& verb,
413 bool overwriteprompt)
414 {
415 #if defined (__WXMSW__) || defined(__UNIX__)
416 return m_impl->SetCommand(cmd, verb, overwriteprompt);
417 #else
418 wxUnusedVar(cmd);
419 wxUnusedVar(verb);
420 wxUnusedVar(overwriteprompt);
421 wxFAIL_MSG(_T("not implemented"));
422 return false;
423 #endif
424 }
425
426 bool wxFileType::SetDefaultIcon(const wxString& cmd, int index)
427 {
428 wxString sTmp = cmd;
429 #ifdef __WXMSW__
430 // VZ: should we do this?
431 // chris elliott : only makes sense in MS windows
432 if ( sTmp.empty() )
433 GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString));
434 #endif
435 wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") );
436
437 #if defined (__WXMSW__) || defined(__UNIX__)
438 return m_impl->SetDefaultIcon (cmd, index);
439 #else
440 wxUnusedVar(index);
441 wxFAIL_MSG(_T("not implemented"));
442 return false;
443 #endif
444 }
445
446
447 // ----------------------------------------------------------------------------
448 // wxMimeTypesManager
449 // ----------------------------------------------------------------------------
450
451 void wxMimeTypesManager::EnsureImpl()
452 {
453 if ( !m_impl )
454 m_impl = new wxMimeTypesManagerImpl;
455 }
456
457 bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
458 const wxString& wildcard)
459 {
460 wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND,
461 wxT("first MIME type can't contain wildcards") );
462
463 // all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
464 if ( wildcard.BeforeFirst(wxT('/')).
465 IsSameAs(mimeType.BeforeFirst(wxT('/')), false) )
466 {
467 wxString strSubtype = wildcard.AfterFirst(wxT('/'));
468
469 if ( strSubtype == wxT("*") ||
470 strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) )
471 {
472 // matches (either exactly or it's a wildcard)
473 return true;
474 }
475 }
476
477 return false;
478 }
479
480 wxMimeTypesManager::wxMimeTypesManager()
481 {
482 m_impl = NULL;
483 }
484
485 wxMimeTypesManager::~wxMimeTypesManager()
486 {
487 if ( m_impl )
488 delete m_impl;
489 }
490
491 bool wxMimeTypesManager::Unassociate(wxFileType *ft)
492 {
493 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
494 return m_impl->Unassociate(ft);
495 #else
496 return ft->Unassociate();
497 #endif
498 }
499
500
501 wxFileType *
502 wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo)
503 {
504 EnsureImpl();
505
506 #if defined(__WXMSW__) || defined(__UNIX__)
507 return m_impl->Associate(ftInfo);
508 #else // other platforms
509 wxUnusedVar(ftInfo);
510 wxFAIL_MSG( _T("not implemented") ); // TODO
511 return NULL;
512 #endif // platforms
513 }
514
515 wxFileType *
516 wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext)
517 {
518 EnsureImpl();
519 wxFileType *ft = m_impl->GetFileTypeFromExtension(ext);
520
521 if ( !ft ) {
522 // check the fallbacks
523 //
524 // TODO linear search is potentially slow, perhaps we should use a
525 // sorted array?
526 size_t count = m_fallbacks.GetCount();
527 for ( size_t n = 0; n < count; n++ ) {
528 if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
529 ft = new wxFileType(m_fallbacks[n]);
530
531 break;
532 }
533 }
534 }
535
536 return ft;
537 }
538
539 wxFileType *
540 wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType)
541 {
542 EnsureImpl();
543 wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType);
544
545 if ( !ft ) {
546 // check the fallbacks
547 //
548 // TODO linear search is potentially slow, perhaps we should use a
549 // sorted array?
550 size_t count = m_fallbacks.GetCount();
551 for ( size_t n = 0; n < count; n++ ) {
552 if ( wxMimeTypesManager::IsOfType(mimeType,
553 m_fallbacks[n].GetMimeType()) ) {
554 ft = new wxFileType(m_fallbacks[n]);
555
556 break;
557 }
558 }
559 }
560
561 return ft;
562 }
563
564 bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback)
565 {
566 EnsureImpl();
567 return m_impl->ReadMailcap(filename, fallback);
568 }
569
570 bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename)
571 {
572 EnsureImpl();
573 return m_impl->ReadMimeTypes(filename);
574 }
575
576 void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
577 {
578 EnsureImpl();
579 for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) {
580 AddFallback(*ft);
581 }
582 }
583
584 size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
585 {
586 EnsureImpl();
587 size_t countAll = m_impl->EnumAllFileTypes(mimetypes);
588
589 // add the fallback filetypes
590 size_t count = m_fallbacks.GetCount();
591 for ( size_t n = 0; n < count; n++ ) {
592 if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) {
593 mimetypes.Add(m_fallbacks[n].GetMimeType());
594 countAll++;
595 }
596 }
597
598 return countAll;
599 }
600
601 void wxMimeTypesManager::Initialize(int mcapStyle,
602 const wxString& sExtraDir)
603 {
604 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
605 EnsureImpl();
606
607 m_impl->Initialize(mcapStyle, sExtraDir);
608 #else
609 (void)mcapStyle;
610 (void)sExtraDir;
611 #endif // Unix
612 }
613
614 // and this function clears all the data from the manager
615 void wxMimeTypesManager::ClearData()
616 {
617 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
618 EnsureImpl();
619
620 m_impl->ClearData();
621 #endif // Unix
622 }
623
624 // ----------------------------------------------------------------------------
625 // global data and wxMimeTypeCmnModule
626 // ----------------------------------------------------------------------------
627
628 // private object
629 static wxMimeTypesManager gs_mimeTypesManager;
630
631 // and public pointer
632 wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager;
633
634 class wxMimeTypeCmnModule: public wxModule
635 {
636 public:
637 wxMimeTypeCmnModule() : wxModule() { }
638 virtual bool OnInit() { return true; }
639 virtual void OnExit()
640 {
641 // this avoids false memory leak allerts:
642 if ( gs_mimeTypesManager.m_impl != NULL )
643 {
644 delete gs_mimeTypesManager.m_impl;
645 gs_mimeTypesManager.m_impl = NULL;
646 gs_mimeTypesManager.m_fallbacks.Clear();
647 }
648 }
649
650 DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule)
651 };
652
653 IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule)
654
655 #endif // wxUSE_MIMETYPE