1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/core/mimetype.cpp
3 // Purpose:     Mac OS X implementation for wx MIME-related classes
4 // Author:      Neil Perkins
5 // Modified by:
6 // Created:     2010-05-15
7 // Copyright:   (C) 2010 Neil Perkins
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 
12 #include "wx/wxprec.h"
13 
14 #ifndef WX_PRECOMP
15 #include "wx/defs.h"
16 #endif
17 
18 #if wxUSE_MIMETYPE
19 
20 #include "wx/osx/mimetype.h"
21 #include "wx/osx/private.h"
22 
23 /////////////////////////////////////////////////////////////////////////////
24 // Helper functions
25 /////////////////////////////////////////////////////////////////////////////
26 
27 
28 // Read a string or array of strings from a CFDictionary for a given key
29 // Return an empty list on error
ReadStringListFromCFDict(CFDictionaryRef dictionary,CFStringRef key)30 wxArrayString ReadStringListFromCFDict( CFDictionaryRef dictionary, CFStringRef key )
31 {
32     // Create an empty list
33     wxArrayString results;
34 
35     // Look up the requested key
36     CFTypeRef valueData = CFDictionaryGetValue( dictionary, key );
37 
38     if( valueData )
39     {
40         // Value is an array
41         if( CFGetTypeID( valueData ) == CFArrayGetTypeID() )
42         {
43             CFArrayRef valueList = reinterpret_cast< CFArrayRef >( valueData );
44 
45             CFTypeRef itemData;
46             wxCFStringRef item;
47 
48             // Look at each item in the array
49             for( CFIndex i = 0, n = CFArrayGetCount( valueList ); i < n; i++ )
50             {
51                 itemData = CFArrayGetValueAtIndex( valueList, i );
52 
53                 // Make sure the item is a string
54                 if( CFGetTypeID( itemData ) == CFStringGetTypeID() )
55                 {
56                     // wxCFStringRef will automatically CFRelease, so an extra CFRetain is needed
57                     item = reinterpret_cast< CFStringRef >( itemData );
58                     wxCFRetain( item.get() );
59 
60                     // Add the string to the list
61                     results.Add( item.AsString() );
62                 }
63             }
64         }
65 
66         // Value is a single string - return a list of one item
67         else if( CFGetTypeID( valueData ) == CFStringGetTypeID() )
68         {
69             // wxCFStringRef will automatically CFRelease, so an extra CFRetain is needed
70             wxCFStringRef value = reinterpret_cast< CFStringRef >( valueData );
71             wxCFRetain( value.get() );
72 
73             // Add the string to the list
74             results.Add( value.AsString() );
75         }
76     }
77 
78     // Return the list. If the dictionary did not contain key,
79     // or contained the wrong data type, the list will be empty
80     return results;
81 }
82 
83 
84 // Given a single CFDictionary representing document type data, check whether
85 // it matches a particular file extension. Return true for a match, false otherwise
CheckDocTypeMatchesExt(CFDictionaryRef docType,CFStringRef requiredExt)86 bool CheckDocTypeMatchesExt( CFDictionaryRef docType, CFStringRef requiredExt )
87 {
88     const static wxCFStringRef extKey( "CFBundleTypeExtensions" );
89 
90     CFTypeRef extData = CFDictionaryGetValue( docType, extKey );
91 
92     if( !extData )
93         return false;
94 
95     if( CFGetTypeID( extData ) == CFArrayGetTypeID() )
96     {
97         CFArrayRef extList = reinterpret_cast< CFArrayRef >( extData );
98         CFTypeRef extItem;
99 
100         for( CFIndex i = 0, n = CFArrayGetCount( extList ); i < n; i++ )
101         {
102             extItem = CFArrayGetValueAtIndex( extList, i );
103 
104             if( CFGetTypeID( extItem ) == CFStringGetTypeID() )
105             {
106                 CFStringRef ext = reinterpret_cast< CFStringRef >( extItem );
107 
108                 if( CFStringCompare( ext, requiredExt, kCFCompareCaseInsensitive ) == kCFCompareEqualTo )
109                     return true;
110             }
111         }
112     }
113 
114     if( CFGetTypeID( extData ) == CFStringGetTypeID() )
115     {
116         CFStringRef ext = reinterpret_cast< CFStringRef >( extData );
117 
118         if( CFStringCompare( ext, requiredExt, kCFCompareCaseInsensitive ) == kCFCompareEqualTo )
119             return true;
120     }
121 
122     return false;
123 }
124 
125 
126 // Given a data structure representing document type data, or a list of such
127 // structures, find the one which matches a particular file extension
128 // The result will be a CFDictionary containining document type data
129 // if a match is found, or null otherwise
GetDocTypeForExt(CFTypeRef docTypeData,CFStringRef requiredExt)130 CFDictionaryRef GetDocTypeForExt( CFTypeRef docTypeData, CFStringRef requiredExt )
131 {
132     if( !docTypeData )
133         return NULL;
134 
135     if( CFGetTypeID( docTypeData ) == CFArrayGetTypeID() )
136     {
137         CFTypeRef item;
138         CFArrayRef docTypes;
139         docTypes = reinterpret_cast< CFArrayRef >( docTypeData );
140 
141         for( CFIndex i = 0, n = CFArrayGetCount( docTypes ); i < n; i++ )
142         {
143             item = CFArrayGetValueAtIndex( docTypes, i );
144 
145             if( CFGetTypeID( item ) == CFDictionaryGetTypeID() )
146             {
147                 CFDictionaryRef docType;
148                 docType = reinterpret_cast< CFDictionaryRef >( item );
149 
150                 if( CheckDocTypeMatchesExt( docType, requiredExt ) )
151                     return docType;
152             }
153         }
154     }
155 
156     if( CFGetTypeID( docTypeData ) == CFDictionaryGetTypeID() )
157     {
158         CFDictionaryRef docType = reinterpret_cast< CFDictionaryRef >( docTypeData );
159 
160         if( CheckDocTypeMatchesExt( docType, requiredExt ) )
161             return docType;
162     }
163 
164     return NULL;
165 }
166 
167 
168 // Given an application bundle reference and the name of an icon file
169 // which is a resource in that bundle, look up the full (posix style)
170 // path to that icon. Returns the path, or an empty wxString on failure
GetPathForIconFile(CFBundleRef bundle,CFStringRef iconFile)171 wxString GetPathForIconFile( CFBundleRef bundle, CFStringRef iconFile )
172 {
173     // If either parameter is NULL there is no hope of success
174     if( !bundle || !iconFile )
175         return wxEmptyString;
176 
177     // Create a range object representing the whole string
178     CFRange wholeString;
179     wholeString.location = 0;
180     wholeString.length = CFStringGetLength( iconFile );
181 
182     // Index of the period in the file name for iconFile
183     UniCharCount periodIndex;
184 
185     // In order to locate the period delimiting the extension,
186     // iconFile must be represented as UniChar[]
187     {
188         // Allocate a buffer and copy in the iconFile string
189         UniChar* buffer = new UniChar[ wholeString.length ];
190         CFStringGetCharacters( iconFile, wholeString, buffer );
191 
192         // Locate the period character
193         OSStatus status = LSGetExtensionInfo( wholeString.length, buffer, &periodIndex );
194 
195         // Deallocate the buffer
196         delete [] buffer;
197 
198         // If the period could not be located it will not be possible to get the URL
199         if( status != noErr || periodIndex == kLSInvalidExtensionIndex )
200             return wxEmptyString;
201     }
202 
203     // Range representing the name part of iconFile
204     CFRange iconNameRange;
205     iconNameRange.location = 0;
206     iconNameRange.length = periodIndex - 1;
207 
208     // Range representing the extension part of iconFile
209     CFRange iconExtRange;
210     iconExtRange.location = periodIndex;
211     iconExtRange.length = wholeString.length - periodIndex;
212 
213     // Get the name and extension strings
214     wxCFStringRef iconName = CFStringCreateWithSubstring( kCFAllocatorDefault, iconFile, iconNameRange );
215     wxCFStringRef iconExt = CFStringCreateWithSubstring( kCFAllocatorDefault, iconFile, iconExtRange );
216 
217     // Now it is possible to query the URL for the icon as a resource
218     wxCFRef< CFURLRef > iconUrl = wxCFRef< CFURLRef >( CFBundleCopyResourceURL( bundle, iconName, iconExt, NULL ) );
219 
220     if( !iconUrl.get() )
221         return wxEmptyString;
222 
223     // All being well, return the icon path
224     return wxCFStringRef( CFURLCopyFileSystemPath( iconUrl, kCFURLPOSIXPathStyle ) ).AsString();
225 }
226 
227 
wxMimeTypesManagerImpl()228 wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
229 {
230 }
231 
~wxMimeTypesManagerImpl()232 wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
233 {
234 }
235 
236 
237 /////////////////////////////////////////////////////////////////////////////
238 // Init / shutdown functions
239 //
240 // The Launch Services / UTI API provides no helpful way of getting a list
241 // of all registered types. Instead the API is focused around looking up
242 // information for a particular file type once you already have some
243 // identifying piece of information. In order to get a list of registered
244 // types it would first be necessary to get a list of all bundles exporting
245 // type information (all application bundles may be sufficient) then look at
246 // the Info.plist file for those bundles and store the type information. As
247 // this would require trawling the hard disk when a wxWidgets program starts
248 // up it was decided instead to load the information lazily.
249 //
250 // If this behaviour really messes up your app, please feel free to implement
251 // the trawling approach (perhaps with a configure switch?). A good place to
252 // start would be CFBundleCreateBundlesFromDirectory( NULL, "/Applications", "app" )
253 /////////////////////////////////////////////////////////////////////////////
254 
255 
Initialize(int WXUNUSED (mailcapStyles),const wxString & WXUNUSED (extraDir))256 void wxMimeTypesManagerImpl::Initialize(int WXUNUSED(mailcapStyles), const wxString& WXUNUSED(extraDir))
257 {
258     // NO-OP
259 }
260 
ClearData()261 void wxMimeTypesManagerImpl::ClearData()
262 {
263     // NO-OP
264 }
265 
266 
267 /////////////////////////////////////////////////////////////////////////////
268 // Lookup functions
269 //
270 // Apple uses a number of different systems for file type information.
271 // As of Spring 2010, these include:
272 //
273 // OS Types / OS Creators
274 // File Extensions
275 // Mime Types
276 // Uniform Type Identifiers (UTI)
277 //
278 // This implementation of the type manager for Mac supports all except OS
279 // Type / OS Creator codes, which have been deprecated for some time with
280 // less and less support in recent versions of OS X.
281 //
282 // The UTI system is the internal system used by OS X, as such it offers a
283 // one-to-one mapping with file types understood by Mac OS X and is the
284 // easiest way to convert between type systems. However, UTI meta-data is
285 // not stored with data files (as of OS X 10.6), instead the OS looks at
286 // the file extension and uses this to determine the UTI. Simillarly, most
287 // applications do not yet advertise the file types they can handle by UTI.
288 //
289 // The result is that no one typing system is suitable for all tasks. Further,
290 // as there is not a one-to-one mapping between type systems for the
291 // description of any given type, it follows that ambiguity cannot be precluded,
292 // whichever system is taken to be the "master".
293 //
294 // In the implementation below I have used UTI as the master key for looking
295 // up file types. Extensions and mime types are mapped to UTIs and the data
296 // for each UTI contains a list of all associated extensions and mime types.
297 // This has the advantage that unknown types will still be assigned a unique
298 // ID, while using any other system as the master could result in conflicts
299 // if there were no mime type assigned to an extension or vice versa. However
300 // there is still plenty of room for ambiguity if two or more applications
301 // are fighting over ownership of a particular type or group of types.
302 //
303 // If this proves to be serious issue it may be helpful to add some slightly
304 // more cleve logic to the code so that the key used to look up a file type is
305 // always first in the list in the resulting wxFileType object. I.e, if you
306 // look up .mpeg3 the list you get back could be .mpeg3, mp3, .mpg3, while
307 // looking up .mp3 would give .mp3, .mpg3, .mpeg3. The simplest way to do
308 // this would probably to keep two separate sets of data, one for lookup
309 // by extetnsion and one for lookup by mime type.
310 //
311 // One other point which may require consideration is handling of unrecognised
312 // types. Using UTI these will be assigned a unique ID of dyn.xxx. This will
313 // result in a wxFileType object being returned, although querying properties
314 // on that object will fail. If it would be more helpful to return NULL in this
315 // case a suitable check can be added.
316 /////////////////////////////////////////////////////////////////////////////
317 
318 // Look up a file type by extension
319 // The extensions if mapped to a UTI
320 // If the requested extension is not know the OS is querried and the results saved
GetFileTypeFromExtension(const wxString & ext)321 wxFileType *wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
322 {
323     wxString uti;
324 
325     const TagMap::const_iterator extItr = m_extMap.find( ext );
326 
327     if( extItr == m_extMap.end() )
328     {
329         wxCFStringRef utiRef = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, wxCFStringRef( ext ), NULL );
330         m_extMap[ ext ] = uti = utiRef.AsString();
331     }
332     else
333         uti = extItr->second;
334 
335     return GetFileTypeFromUti( uti );
336 }
337 
338 // Look up a file type by mime type
339 // The mime type is mapped to a UTI
340 // If the requested extension is not know the OS is querried and the results saved
GetFileTypeFromMimeType(const wxString & mimeType)341 wxFileType *wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
342 {
343     wxString uti;
344 
345     const TagMap::const_iterator mimeItr = m_mimeMap.find( mimeType );
346 
347     if( mimeItr == m_mimeMap.end() )
348     {
349         wxCFStringRef utiRef = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, wxCFStringRef( mimeType ), NULL );
350         m_mimeMap[ mimeType ] = uti = utiRef.AsString();
351     }
352     else
353         uti = mimeItr->second;
354 
355     return GetFileTypeFromUti( uti );
356 }
357 
358 // Look up a file type by UTI
359 // If the requested extension is not know the OS is querried and the results saved
GetFileTypeFromUti(const wxString & uti)360 wxFileType *wxMimeTypesManagerImpl::GetFileTypeFromUti(const wxString& uti)
361 {
362     UtiMap::const_iterator utiItr = m_utiMap.find( uti );
363 
364     if( utiItr == m_utiMap.end() )
365     {
366         LoadTypeDataForUti( uti );
367         LoadDisplayDataForUti( uti );
368     }
369 
370     wxFileType* const ft = new wxFileType;
371     ft->m_impl->m_uti = uti;
372     ft->m_impl->m_manager = this;
373 
374     return ft;
375 }
376 
377 
378 /////////////////////////////////////////////////////////////////////////////
379 // Load functions
380 //
381 // These functions query the OS for information on a particular file type
382 /////////////////////////////////////////////////////////////////////////////
383 
384 
385 // Look up all extensions and mime types associated with a UTI
LoadTypeDataForUti(const wxString & uti)386 void wxMimeTypesManagerImpl::LoadTypeDataForUti(const wxString& uti)
387 {
388     // Keys in to the UTI declaration plist
389     const static wxCFStringRef tagsKey( "UTTypeTagSpecification" );
390     const static wxCFStringRef extKey( "public.filename-extension" );
391     const static wxCFStringRef mimeKey( "public.mime-type" );
392 
393     // Get the UTI as a CFString
394     wxCFStringRef utiRef( uti );
395 
396     // Get a copy of the UTI declaration
397     wxCFRef< CFDictionaryRef > utiDecl;
398     utiDecl = wxCFRef< CFDictionaryRef >( UTTypeCopyDeclaration( utiRef ) );
399 
400     if( !utiDecl )
401         return;
402 
403     // Get the tags spec (the section of a UTI declaration containing mappings to other type systems)
404     CFTypeRef tagsData = CFDictionaryGetValue( utiDecl, tagsKey );
405 
406     if( CFGetTypeID( tagsData ) != CFDictionaryGetTypeID() )
407         return;
408 
409     CFDictionaryRef tags = reinterpret_cast< CFDictionaryRef >( tagsData );
410 
411     // Read tags for extensions and mime types
412     m_utiMap[ uti ].extensions = ReadStringListFromCFDict( tags, extKey );
413     m_utiMap[ uti ].mimeTypes = ReadStringListFromCFDict( tags, mimeKey );
414 }
415 
416 
417 // Look up the (locale) display name and icon file associated with a UTI
LoadDisplayDataForUti(const wxString & uti)418 void wxMimeTypesManagerImpl::LoadDisplayDataForUti(const wxString& uti)
419 {
420     // Keys in to Info.plist
421     const static wxCFStringRef docTypesKey( "CFBundleDocumentTypes" );
422     const static wxCFStringRef descKey( "CFBundleTypeName" );
423     const static wxCFStringRef iconKey( "CFBundleTypeIconFile" );
424 
425     wxCFStringRef cfuti(uti);
426 
427     wxCFStringRef ext = UTTypeCopyPreferredTagWithClass( cfuti, kUTTagClassFilenameExtension );
428 
429     // Look up the preferred application
430     wxCFRef<CFURLRef> appUrl = LSCopyDefaultApplicationURLForContentType( cfuti, kLSRolesAll, NULL);
431 
432     if( !appUrl )
433         return;
434 
435     // Create a bundle object for that application
436     wxCFRef< CFBundleRef > bundle;
437     bundle = wxCFRef< CFBundleRef >( CFBundleCreate( kCFAllocatorDefault, appUrl ) );
438 
439     if( !bundle )
440         return;
441 
442     // Also get the open command while we have the bundle
443     wxCFStringRef cfsAppPath(CFURLCopyFileSystemPath(appUrl, kCFURLPOSIXPathStyle));
444     m_utiMap[ uti ].application = cfsAppPath.AsString();
445 
446     // Get all the document type data in this bundle
447     CFTypeRef docTypeData;
448     docTypeData = CFBundleGetValueForInfoDictionaryKey( bundle, docTypesKey );
449 
450     if( !docTypeData )
451         return;
452 
453     // Find the document type entry that matches ext
454     CFDictionaryRef docType;
455     docType = GetDocTypeForExt( docTypeData, ext );
456 
457     if( !docType )
458         return;
459 
460     // Get the display name for docType
461     wxCFStringRef description = reinterpret_cast< CFStringRef >( CFDictionaryGetValue( docType, descKey ) );
462     wxCFRetain( description.get() );
463     m_utiMap[ uti ].description = description.AsString();
464 
465     // Get the icon path for docType
466     CFStringRef iconFile = reinterpret_cast< CFStringRef > ( CFDictionaryGetValue( docType, iconKey ) );
467     m_utiMap[ uti ].iconLoc.SetFileName( GetPathForIconFile( bundle, iconFile ) );
468 }
469 
470 
471 
472 /////////////////////////////////////////////////////////////////////////////
473 // The remaining functionality from the public interface of
474 // wxMimeTypesManagerImpl is not implemented.
475 //
476 // Please see the note further up this file on Initialise/Clear to explain why
477 // EnumAllFileTypes is not available.
478 //
479 // Some thought will be needed before implementing Associate / Unassociate
480 // for OS X to ensure proper integration with the many file type and
481 // association mechanisms already used by the OS. Leaving these methods as
482 // NO-OP on OS X and asking client apps to put suitable entries in their
483 // Info.plist files when building their OS X bundle may well be the
484 // correct solution.
485 /////////////////////////////////////////////////////////////////////////////
486 
487 
EnumAllFileTypes(wxArrayString & WXUNUSED (mimetypes))488 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& WXUNUSED(mimetypes))
489 {
490     return 0;
491 }
492 
Associate(const wxFileTypeInfo & WXUNUSED (ftInfo))493 wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& WXUNUSED(ftInfo))
494 {
495     return 0;
496 }
497 
Unassociate(wxFileType * WXUNUSED (ft))498 bool wxMimeTypesManagerImpl::Unassociate(wxFileType *WXUNUSED(ft))
499 {
500     return false;
501 }
502 
503 
504 /////////////////////////////////////////////////////////////////////////////
505 // Getter methods
506 //
507 // These methods are private and should only ever be called by wxFileTypeImpl
508 // after the required information has been loaded. It should not be possible
509 // to get a wxFileTypeImpl for a UTI without information for that UTI being
510 // querried, however it is possible that some information may not have been
511 // found.
512 /////////////////////////////////////////////////////////////////////////////
513 
514 
515 
GetExtensions(const wxString & uti,wxArrayString & extensions)516 bool wxMimeTypesManagerImpl::GetExtensions(const wxString& uti, wxArrayString& extensions)
517 {
518     const UtiMap::const_iterator itr = m_utiMap.find( uti );
519 
520     if( itr == m_utiMap.end() || itr->second.extensions.GetCount() < 1 )
521     {
522         extensions.Clear();
523         return false;
524     }
525 
526     extensions = itr->second.extensions;
527     return true;
528 }
529 
GetMimeType(const wxString & uti,wxString * mimeType)530 bool wxMimeTypesManagerImpl::GetMimeType(const wxString& uti, wxString *mimeType)
531 {
532     const UtiMap::const_iterator itr = m_utiMap.find( uti );
533 
534     if( itr == m_utiMap.end() || itr->second.mimeTypes.GetCount() < 1 )
535     {
536         mimeType->clear();
537         return false;
538     }
539 
540     *mimeType = itr->second.mimeTypes[ 0 ];
541     return true;
542 }
543 
GetMimeTypes(const wxString & uti,wxArrayString & mimeTypes)544 bool wxMimeTypesManagerImpl::GetMimeTypes(const wxString& uti, wxArrayString& mimeTypes)
545 {
546     const UtiMap::const_iterator itr = m_utiMap.find( uti );
547 
548     if( itr == m_utiMap.end() || itr->second.mimeTypes.GetCount() < 1 )
549     {
550         mimeTypes.Clear();
551         return false;
552     }
553 
554     mimeTypes = itr->second.mimeTypes;
555     return true;
556 }
557 
GetIcon(const wxString & uti,wxIconLocation * iconLoc)558 bool wxMimeTypesManagerImpl::GetIcon(const wxString& uti, wxIconLocation *iconLoc)
559 {
560     const UtiMap::const_iterator itr = m_utiMap.find( uti );
561 
562     if( itr == m_utiMap.end() || !itr->second.iconLoc.IsOk() )
563     {
564         *iconLoc = wxIconLocation();
565         return false;
566     }
567 
568     *iconLoc = itr->second.iconLoc;
569     return true;
570 }
571 
GetDescription(const wxString & uti,wxString * desc)572 bool wxMimeTypesManagerImpl::GetDescription(const wxString& uti, wxString *desc)
573 {
574     const UtiMap::const_iterator itr = m_utiMap.find( uti );
575 
576     if( itr == m_utiMap.end() || itr->second.description.empty() )
577     {
578         desc->clear();
579         return false;
580     }
581 
582     *desc = itr->second.description;
583     return true;
584 }
585 
GetApplication(const wxString & uti,wxString * command)586 bool wxMimeTypesManagerImpl::GetApplication(const wxString& uti, wxString *command)
587 {
588     const UtiMap::const_iterator itr = m_utiMap.find( uti );
589 
590     if( itr == m_utiMap.end() )
591     {
592         command->clear();
593         return false;
594     }
595 
596     *command = itr->second.application;
597     return true;
598 }
599 
600 /////////////////////////////////////////////////////////////////////////////
601 // The remaining functionality has not yet been implemented for OS X
602 /////////////////////////////////////////////////////////////////////////////
603 
wxFileTypeImpl()604 wxFileTypeImpl::wxFileTypeImpl()
605 {
606 }
607 
~wxFileTypeImpl()608 wxFileTypeImpl::~wxFileTypeImpl()
609 {
610 }
611 
612 // Query wxMimeTypesManagerImple to get real information for a file type
GetExtensions(wxArrayString & extensions) const613 bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) const
614 {
615     return m_manager->GetExtensions( m_uti, extensions );
616 }
617 
GetMimeType(wxString * mimeType) const618 bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
619 {
620     return m_manager->GetMimeType( m_uti, mimeType );
621 }
622 
GetMimeTypes(wxArrayString & mimeTypes) const623 bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const
624 {
625     return m_manager->GetMimeTypes( m_uti, mimeTypes );
626 }
627 
GetIcon(wxIconLocation * iconLoc) const628 bool wxFileTypeImpl::GetIcon(wxIconLocation *iconLoc) const
629 {
630     return m_manager->GetIcon( m_uti, iconLoc );
631 }
632 
GetDescription(wxString * desc) const633 bool wxFileTypeImpl::GetDescription(wxString *desc) const
634 {
635     return m_manager->GetDescription( m_uti, desc );
636 }
637 
638 namespace
639 {
640 
641 // Helper function for GetOpenCommand(): returns the string surrounded by
642 // (singly) quotes if it contains spaces.
QuoteIfNecessary(const wxString & path)643 wxString QuoteIfNecessary(const wxString& path)
644 {
645     wxString result(path);
646 
647     if ( path.find(' ') != wxString::npos )
648     {
649         result.insert(0, "'");
650         result.append("'");
651     }
652 
653     return result;
654 }
655 
656 } // anonymous namespace
657 
GetOpenCommand(wxString * openCmd,const wxFileType::MessageParameters & params) const658 bool wxFileTypeImpl::GetOpenCommand(wxString *openCmd, const wxFileType::MessageParameters& params) const
659 {
660     wxString application;
661     if ( !m_manager->GetApplication(m_uti, &application) )
662         return false;
663 
664     *openCmd << QuoteIfNecessary(application)
665              << ' ' << QuoteIfNecessary(params.GetFileName());
666 
667     return true;
668 }
669 
GetPrintCommand(wxString * WXUNUSED (printCmd),const wxFileType::MessageParameters & WXUNUSED (params)) const670 bool wxFileTypeImpl::GetPrintCommand(wxString *WXUNUSED(printCmd), const wxFileType::MessageParameters& WXUNUSED(params)) const
671 {
672     return false;
673 }
674 
GetAllCommands(wxArrayString * WXUNUSED (verbs),wxArrayString * WXUNUSED (commands),const wxFileType::MessageParameters & WXUNUSED (params)) const675 size_t wxFileTypeImpl::GetAllCommands(wxArrayString *WXUNUSED(verbs), wxArrayString *WXUNUSED(commands), const wxFileType::MessageParameters& WXUNUSED(params)) const
676 {
677     return false;
678 }
679 
SetCommand(const wxString & WXUNUSED (cmd),const wxString & WXUNUSED (verb),bool WXUNUSED (overwriteprompt))680 bool wxFileTypeImpl::SetCommand(const wxString& WXUNUSED(cmd), const wxString& WXUNUSED(verb), bool WXUNUSED(overwriteprompt))
681 {
682     return false;
683 }
684 
SetDefaultIcon(const wxString & WXUNUSED (strIcon),int WXUNUSED (index))685 bool wxFileTypeImpl::SetDefaultIcon(const wxString& WXUNUSED(strIcon), int WXUNUSED(index))
686 {
687     return false;
688 }
689 
Unassociate(wxFileType * WXUNUSED (ft))690 bool wxFileTypeImpl::Unassociate(wxFileType *WXUNUSED(ft))
691 {
692     return false;
693 }
694 
695 wxString
GetExpandedCommand(const wxString & WXUNUSED (verb),const wxFileType::MessageParameters & WXUNUSED (params)) const696 wxFileTypeImpl::GetExpandedCommand(const wxString& WXUNUSED(verb),
697                                    const wxFileType::MessageParameters& WXUNUSED(params)) const
698 {
699     return wxString();
700 }
701 
702 #endif // wxUSE_MIMETYPE
703 
704 
705