1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/mimetype.cpp 
   3 // Purpose:     Mac Carbon implementation for wx MIME-related classes 
   8 // Copyright:   (c) 2005 Ryan Norton (<wxprojects@comcast.net>) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 //  TODO: Search Info[-macos](classic).plist dictionary in addition 
  14 //  to Internet Config database. 
  16 //  Maybe try a brainstorm a way to change the wxMimeTypesManager API 
  17 //  to get info from a file instead/addition to current get all stuff 
  18 //  API so that we can use Launch Services to get MIME type info. 
  20 //  Implement GetIcon from one of the FinderInfo functions - or 
  21 //  use Launch Services and search that app's plist for the icon. 
  23 //  Put some special juice in for the print command. 
  26 // for compilers that support precompilation, includes "wx.h". 
  27 #include "wx/wxprec.h" 
  35 #include "wx/mac/mimetype.h" 
  38     #include "wx/dynarray.h" 
  39     #include "wx/string.h" 
  49 #include "wx/confbase.h" 
  51 #include "wx/mac/private.h" 
  53 // other standard headers 
  57     #include <InternetConfig.h> 
  58     #include <CoreServices.h> 
  62 //   START CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html) 
  64 // IsRemoteVolume can be used to find out if the 
  65 // volume referred to by vRefNum is a remote volume 
  66 // located somewhere on a network. the volume's attribute 
  67 // flags (copied from the GetVolParmsInfoBuffer structure) 
  68 // are returned in the longword pointed to by vMAttrib. 
  69 OSErr 
IsRemoteVolume(short vRefNum
, Boolean 
*isRemote
, long *vMAttrib
) 
  72     GetVolParmsInfoBuffer volinfo
; 
  75     volPB
.ioParam
.ioVRefNum 
= vRefNum
; 
  76     volPB
.ioParam
.ioNamePtr 
= NULL
; 
  77     volPB
.ioParam
.ioBuffer 
= (Ptr
)&volinfo
; 
  78     volPB
.ioParam
.ioReqCount 
= sizeof(volinfo
); 
  79     err 
= PBHGetVolParmsSync( &volPB 
); 
  82         *isRemote 
= (volinfo
.vMServerAdr 
!= 0); 
  83         *vMAttrib 
= volinfo
.vMAttrib
; 
  89 // BuildVolumeList fills the array pointed to by vols with 
  90 // a list of the currently mounted volumes.  If includeRemote 
  91 // is true, then remote server volumes will be included in 
  92 // the list.  When remote server volumes are included in the 
  93 // list, they will be added to the end of the list.  On entry, 
  94 // *count should contain the size of the array pointed to by 
  95 // vols.  On exit, *count will be set to the number of id numbers 
  96 // placed in the array. If vMAttribMask is non-zero, then 
  97 // only volumes with matching attributes are added to the 
  98 // list of volumes. bits in the vMAttribMask should use the 
  99 // same encoding as bits in the vMAttrib field of 
 100 // the GetVolParmsInfoBuffer structure. 
 101 OSErr 
BuildVolumeList(Boolean includeRemote
, short *vols
, 
 102         long *count
, long vMAttribMask
) 
 104     HParamBlockRec volPB
; 
 107     long nlocal
, nremote
; 
 110     // set up and check parameters 
 111     volPB
.volumeParam
.ioNamePtr 
= NULL
; 
 112     nlocal 
= nremote 
= 0; 
 116     // iterate through volumes 
 117     for (volPB
.volumeParam
.ioVolIndex 
= 1; 
 118         PBHGetVInfoSync(&volPB
) == noErr
; 
 119         volPB
.volumeParam
.ioVolIndex
++) 
 121         // skip remote volumes, if necessary 
 122         err 
= IsRemoteVolume(volPB
.volumeParam
.ioVRefNum
, &isRemote
, &vMAttrib
); 
 126         if ((includeRemote 
|| !isRemote
) && ((vMAttrib 
& vMAttribMask
) == vMAttribMask
)) 
 128             // add local volumes at the front; remote volumes at the end 
 130                 vols
[nlocal 
+ nremote
++] = volPB
.volumeParam
.ioVRefNum
; 
 137                         nremote 
* sizeof(short) ); 
 138                 vols
[nlocal
++] = volPB
.volumeParam
.ioVRefNum
; 
 142             if ((nlocal 
+ nremote
) >= *count
) 
 148     *count 
= (nlocal 
+ nremote
); 
 154 // FindApplication iterates through mounted volumes 
 155 // searching for an application with the given creator 
 156 // type.  If includeRemote is true, then remote volumes 
 157 // will be searched (after local ones) for an application 
 158 // with the creator type. 
 160 // Hacked to output to appName 
 164 OSErr 
FindApplication(OSType appCreator
, Boolean includeRemote
, Str255 appName
, FSSpec
* appSpec
) 
 166     short rRefNums
[kMaxVols
]; 
 171     // get a list of volumes - with desktop files 
 173     err 
= BuildVolumeList(includeRemote
, rRefNums
, &volCount
, (1 << bHasDesktopMgr
) ); 
 177     // iterate through the list 
 178     for (i
=0; i
<volCount
; i
++) 
 180         // has a desktop file? 
 181         desktopPB
.ioCompletion 
= NULL
; 
 182         desktopPB
.ioVRefNum 
= rRefNums
[i
]; 
 183         desktopPB
.ioNamePtr 
= NULL
; 
 184         desktopPB
.ioIndex 
= 0; 
 185         err 
= PBDTGetPath( &desktopPB 
); 
 189         // has the correct app?? 
 190         desktopPB
.ioFileCreator 
= appCreator
; 
 191         desktopPB
.ioNamePtr 
= appName
; 
 192         err 
= PBDTGetAPPLSync( &desktopPB 
); 
 196         // make a file spec referring to it 
 197         err 
= FSMakeFSSpec( rRefNums
[i
], desktopPB
.ioAPPLParID
, appName
, appSpec 
); 
 208 // END CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html) 
 210 // yeah, duplicated code 
 211 pascal OSErr 
FSpGetFullPath( const FSSpec 
*spec
, 
 212     short *fullPathLength
, 
 215     OSErr result
, realResult
; 
 223     realResult 
= result 
= noErr
; 
 225   // work around Nav Services "bug" (it returns invalid FSSpecs with empty names) 
 227     if ( spec
->name
[0] == 0 ) 
 229         result 
= FSMakeFSSpecCompat(spec
->vRefNum
, spec
->parID
, spec
->name
, &tempSpec
); 
 235     // Make a copy of the input FSSpec that can be modified 
 236     BlockMoveData( spec
, &tempSpec
, sizeof(FSSpec
) ); 
 238     if ( result 
== noErr 
) 
 240         if ( tempSpec
.parID 
== fsRtParID 
) 
 242             // object is a volume 
 243             // Add a colon to make it a full pathname 
 245             tempSpec
.name
[tempSpec
.name
[0]] = ':'; 
 248             result 
= PtrToHand(&tempSpec
.name
[1], fullPath
, tempSpec
.name
[0]); 
 252             // object isn't a volume 
 254             // Is the object a file or a directory? 
 255             pb
.dirInfo
.ioNamePtr 
= tempSpec
.name
; 
 256             pb
.dirInfo
.ioVRefNum 
= tempSpec
.vRefNum
; 
 257             pb
.dirInfo
.ioDrDirID 
= tempSpec
.parID
; 
 258             pb
.dirInfo
.ioFDirIndex 
= 0; 
 259             result 
= PBGetCatInfoSync( &pb 
); 
 261             // Allow file/directory name at end of path to not exist. 
 263             if ((result 
== noErr
) || (result 
== fnfErr
)) 
 265                 // if the object is a directory, append a colon so full pathname ends with colon 
 266                 if ((result 
== noErr
) && (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0) 
 269                     tempSpec
.name
[tempSpec
.name
[0]] = ':'; 
 272                 // Put the object name in first 
 273                 result 
= PtrToHand( &tempSpec
.name
[1], fullPath
, tempSpec
.name
[0] ); 
 274                 if ( result 
== noErr 
) 
 276                     // Get the ancestor directory names 
 277                     pb
.dirInfo
.ioNamePtr 
= tempSpec
.name
; 
 278                     pb
.dirInfo
.ioVRefNum 
= tempSpec
.vRefNum
; 
 279                     pb
.dirInfo
.ioDrParID 
= tempSpec
.parID
; 
 281                     // loop until we have an error or find the root directory 
 284                         pb
.dirInfo
.ioFDirIndex 
= -1; 
 285                         pb
.dirInfo
.ioDrDirID 
= pb
.dirInfo
.ioDrParID
; 
 286                         result 
= PBGetCatInfoSync(&pb
); 
 287                         if ( result 
== noErr 
) 
 289                             // Append colon to directory name 
 291                             tempSpec
.name
[tempSpec
.name
[0]] = ':'; 
 293                             // Add directory name to beginning of fullPath 
 294                             (void)Munger(*fullPath
, 0, NULL
, 0, &tempSpec
.name
[1], tempSpec
.name
[0]); 
 298                     while ( (result 
== noErr
) && (pb
.dirInfo
.ioDrDirID 
!= fsRtDirID
) ); 
 304     if ( result 
== noErr 
) 
 307         *fullPathLength 
= GetHandleSize( *fullPath 
); 
 308         result 
= realResult
;  // return realResult in case it was fnfErr 
 312         // Dispose of the handle and return NULL and zero length 
 313         if ( *fullPath 
!= NULL 
) 
 315             DisposeHandle( *fullPath 
); 
 325 // On the mac there are two ways to open a file - one is through apple events and the 
 326 // finder, another is through mime types. 
 328 // So, really there are two ways to implement wxFileType... 
 330 // Mime types are only available on OS 8.1+ through the InternetConfig API 
 332 // Much like the old-style file manager, it has 3 levels of flexibility for its methods - 
 333 // Low - which means you have to iterate yourself through the mime database 
 334 // Medium - which lets you sort of cache the database if you want to use lowlevel functions 
 335 // High - which requires access to the database every time 
 337 // We want to be efficient (i.e. professional :) ) about it, so we use a combo of low 
 338 // and mid-level functions 
 340 // TODO: Should we call ICBegin/ICEnd?  Then where? 
 344 inline void wxLogMimeDebug(const wxChar
* szMsg
, OSStatus status
) 
 346     wxLogDebug(wxString::Format(wxT("%s  LINE:%i  OSERROR:%i"), szMsg
, __LINE__
, (int)status
)); 
 349 // in case we're compiling in non-GUI mode 
 350 class WXDLLEXPORT wxIcon
; 
 352 bool wxFileTypeImpl::SetCommand(const wxString
& cmd
, const wxString
& verb
, bool overwriteprompt
) 
 354     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 359 bool wxFileTypeImpl::SetDefaultIcon(const wxString
& strIcon
, int index
) 
 361     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 366 bool wxFileTypeImpl::GetOpenCommand(wxString 
*openCmd
, 
 367                                const wxFileType::MessageParameters
& params
) const 
 369     wxString cmd 
= GetCommand(wxT("open")); 
 371     *openCmd 
= wxFileType::ExpandCommand(cmd
, params
); 
 373     return !openCmd
->empty(); 
 377 wxFileTypeImpl::GetPrintCommand( 
 379     const wxFileType::MessageParameters
& params
) const 
 381     wxString cmd 
= GetCommand(wxT("print")); 
 383     *printCmd 
= wxFileType::ExpandCommand(cmd
, params
); 
 385     return !printCmd
->empty(); 
 389 // Internet Config vs. Launch Services 
 391 // From OS 8 on there was internet config... 
 392 // However, OSX and its finder does not use info 
 393 // from Internet Config at all - the Internet Config 
 394 // database ONLY CONTAINS APPS THAT ARE CLASSIC APPS 
 395 // OR REGISTERED THROUGH INTERNET CONFIG 
 397 // Therefore on OSX in order for the open command to be useful 
 398 // we need to go straight to launch services 
 401 #if defined(__DARWIN__) 
 403 //on darwin, use launch services 
 404 #include <ApplicationServices/ApplicationServices.h> 
 406 wxString 
wxFileTypeImpl::GetCommand(const wxString
& verb
) const 
 408     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 410     if (verb 
== wxT("open")) 
 413         ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
, 
 414                        (Handle
) m_manager
->m_hDatabase
, 
 417         wxString sCurrentExtension 
= wxMacMakeStringFromPascal(entry
.extension
); 
 418         sCurrentExtension 
= sCurrentExtension
.Right(sCurrentExtension
.length()-1 ); 
 420         //type, creator, ext, roles, outapp (FSRef), outappurl 
 421         CFURLRef cfurlAppPath
; 
 422         OSStatus status 
= LSGetApplicationForInfo( kLSUnknownType
, 
 424             wxMacCFStringHolder(sCurrentExtension
, wxLocale::GetSystemEncoding()), 
 431             CFStringRef cfsUnixPath 
= CFURLCopyFileSystemPath(cfurlAppPath
, kCFURLPOSIXPathStyle
); 
 432             CFRelease(cfurlAppPath
); 
 435             // Since a filename might have spaces in it, so surround it with quotes 
 442                     + wxMacCFStringHolder(cfsUnixPath
).AsString(wxLocale::GetSystemEncoding()) 
 443                     + wxString(wxT("'")); 
 450             wxLogDebug(wxString::Format(wxT("%i - %s - %i"), 
 452             wxT("LSGetApplicationForInfo failed."), 
 457     return wxEmptyString
; 
 460 #else //carbon/classic implementation 
 463 wxString 
wxFileTypeImpl::GetCommand(const wxString
& verb
) const 
 465     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 467     if (verb 
== wxT("open")) 
 470         ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
, 
 471                        (Handle
) m_manager
->m_hDatabase
, 
 474         //The entry in the mimetype database only contains the app 
 475         //that's registered - it may not exist... we need to remap the creator 
 476         //type and find the right application 
 478         // THIS IS REALLY COMPLICATED :\. 
 479         // There are a lot of conversions going on here. 
 482         OSErr err 
= FindApplication( entry
.fileCreator
, false, outName
, &outSpec 
); 
 484             return wxEmptyString
; 
 486         Handle outPathHandle
; 
 488         err 
= FSpGetFullPath( &outSpec
, &outPathSize
, &outPathHandle 
); 
 491             char* szPath 
= *outPathHandle
; 
 492             wxString 
sClassicPath(szPath
, wxConvLocal
, outPathSize
); 
 494 #if defined(__DARWIN__) 
 495             // Classic Path --> Unix (OSX) Path 
 496             CFURLRef finalURL 
= CFURLCreateWithFileSystemPath( 
 498                 wxMacCFStringHolder(sClassicPath
, wxLocale::GetSystemEncoding()), 
 500                 false ); //false == not a directory 
 502             //clean up memory from the classic path handle 
 503             DisposeHandle( outPathHandle 
); 
 507                 CFStringRef cfsUnixPath 
= CFURLCopyFileSystemPath(finalURL
, kCFURLPOSIXPathStyle
); 
 512                     return wxMacCFStringHolder(cfsUnixPath
).AsString(wxLocale::GetSystemEncoding()); 
 514 #else //classic HFS path acceptable 
 520             wxLogMimeDebug(wxT("FSpGetFullPath failed."), (OSStatus
)err
); 
 524     return wxEmptyString
; 
 528 bool wxFileTypeImpl::GetDescription(wxString 
*desc
) const 
 530     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 533     ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
, 
 534         (Handle
) m_manager
->m_hDatabase
, m_lIndex
, &entry 
); 
 536     *desc 
= wxMacMakeStringFromPascal( entry
.entryName 
); 
 541 bool wxFileTypeImpl::GetExtensions(wxArrayString
& extensions
) 
 543     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 546     ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
, 
 547         (Handle
) m_manager
->m_hDatabase
, m_lIndex
, &entry 
); 
 549     //entry has period in it 
 550     wxString sCurrentExtension 
= wxMacMakeStringFromPascal( entry
.extension 
); 
 551     extensions
.Add( sCurrentExtension
.Right( sCurrentExtension
.length() - 1 ) ); 
 556 bool wxFileTypeImpl::GetMimeType(wxString 
*mimeType
) const 
 558     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 561     ICGetMapEntry( (ICInstance
) m_manager
->m_hIC
, 
 562         (Handle
) m_manager
->m_hDatabase
, m_lIndex
, &entry 
); 
 564     *mimeType 
= wxMacMakeStringFromPascal(entry
.MIMEType
); 
 569 bool wxFileTypeImpl::GetMimeTypes(wxArrayString
& mimeTypes
) const 
 584 bool wxFileTypeImpl::GetIcon(wxIconLocation 
*WXUNUSED(icon
)) const 
 586     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 588     // no such file type or no value or incorrect icon entry 
 592 size_t wxFileTypeImpl::GetAllCommands(wxArrayString 
* verbs
, 
 593     wxArrayString 
* commands
, 
 594     const wxFileType::MessageParameters
& params
) const 
 596     wxASSERT_MSG( m_manager 
!= NULL 
, wxT("Bad wxFileType") ); 
 601     if (GetOpenCommand(&sCommand
, params
)) 
 603         verbs
->Add(wxString(wxT("open"))); 
 604         commands
->Add(sCommand
); 
 611 void wxMimeTypesManagerImpl::Initialize(int mailcapStyles
, const wxString
& extraDir
) 
 613     wxASSERT_MSG(m_hIC 
== NULL
, wxT("Already initialized wxMimeTypesManager!")); 
 615     // some apps (non-wx) use the 'plst' resource instead 
 617     CFBundleRef cfbMain 
= CFBundleGetMainBundle(); 
 618     wxCFDictionary 
cfdInfo( CFBundleGetInfoDictionary(cfbMain
), wxCF_RETAIN 
); 
 620     cfdInfo
.PrintOut(sLog
); 
 624     // start Internet Config - log if there's an error 
 625     // the second param is the signature of the application, also known 
 626     // as resource ID 0.  However, as per some recent discussions, we may not 
 627     // have a signature for this app, so a generic 'APPL' which is the executable 
 628     // type will work for now. 
 629     OSStatus status 
= ICStart( (ICInstance
*)&m_hIC
, 'APPL' ); 
 633         wxLogDebug(wxT("Could not initialize wxMimeTypesManager!")); 
 641     m_hDatabase 
= (void**) NewHandle(0); 
 642     status 
= ICFindPrefHandle( (ICInstance
) m_hIC
, kICMapping
, &attr
, (Handle
) m_hDatabase 
); 
 644     //the database file can be corrupt (on OSX its 
 645     //~/Library/Preferences/com.apple.internetconfig.plist) 
 650         wxLogDebug(wxT("Corrupt MIME database!")); 
 654     //obtain the number of entries in the map 
 655     status 
= ICCountMapEntries( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, &m_lCount 
); 
 656     wxASSERT( status 
== noErr 
); 
 663     for (long i 
= 1; i 
<= m_lCount
; ++i
) 
 665         OSStatus status 
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry 
); 
 669             wxString sCreator 
= wxMacMakeStringFromPascal(entry
.creatorAppName
); 
 670             wxString sCurrentExtension 
= wxMacMakeStringFromPascal(entry
.extension
); 
 671             wxString sMIMEType 
= wxMacMakeStringFromPascal(entry
.MIMEType
); 
 674             impl
.Init(this, pos
); 
 676             if (sMIMEType 
== wxT("text/html") && sCurrentExtension 
== wxT(".html")) 
 680                 impl
.GetOpenCommand( &cmd
, wxFileType::MessageParameters (wxT("http://www.google.com"))); 
 681                 wxPrintf(wxT("APP: [%s]\n"), cmd
.c_str()); 
 688 void wxMimeTypesManagerImpl::ClearData() 
 692         DisposeHandle( (Handle
)m_hDatabase 
); 
 694         // this can return an error, but we don't really care that much about it 
 695         ICStop( (ICInstance
)m_hIC 
); 
 701 //  Q) Iterating through the map - why does it use if (err == noErr) instead of just asserting? 
 702 //  A) Some intermediate indexes are bad while subsequent ones may be good.  Its wierd, I know. 
 705 // extension -> file type 
 706 wxFileType
* wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString
& e
) 
 708     wxASSERT_MSG( m_hIC 
!= NULL
, wxT("wxMimeTypesManager not Initialized!") ); 
 710     //low level functions - iterate through the database 
 714     for (long i 
= 1; i 
<= m_lCount
; ++i
) 
 716         OSStatus status 
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry 
); 
 720             wxString sCurrentExtension 
= wxMacMakeStringFromPascal(entry
.extension
); 
 721             if ( sCurrentExtension
.Right(sCurrentExtension
.length() - 1) == e 
) // entry has period in it 
 723                 wxFileType
* pFileType 
= new wxFileType(); 
 724                 pFileType
->m_impl
->Init((wxMimeTypesManagerImpl
*)this, pos
); 
 734 // MIME type -> extension -> file type 
 735 wxFileType
* wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString
& mimeType
) 
 737     wxASSERT_MSG( m_hIC 
!= NULL
, wxT("wxMimeTypesManager not Initialized!") ); 
 742     // low level functions - iterate through the database 
 743     for (long i 
= 1; i 
<= m_lCount
; ++i
) 
 745         OSStatus status 
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry 
); 
 746         wxASSERT_MSG( status 
== noErr
, wxString::Format(wxT("Error: %d"), (int)status
) ); 
 750             if ( wxMacMakeStringFromPascal(entry
.MIMEType
) == mimeType
) 
 752                 wxFileType
* pFileType 
= new wxFileType(); 
 753                 pFileType
->m_impl
->Init((wxMimeTypesManagerImpl
*)this, pos
); 
 763 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString
& mimetypes
) 
 765     wxASSERT_MSG( m_hIC 
!= NULL
, wxT("wxMimeTypesManager not Initialized!") ); 
 768     long pos
, lStartCount
; 
 770     // low level functions - iterate through the database 
 771     lStartCount 
= (long) mimetypes
.GetCount(); 
 772     for (long i 
= 1; i 
<= m_lCount
; ++i
) 
 774         OSStatus status 
= ICGetIndMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, i
, &pos
, &entry 
); 
 775         if ( status 
== noErr 
) 
 776             mimetypes
.Add( wxMacMakeStringFromPascal(entry
.MIMEType
) ); 
 779     return mimetypes
.GetCount() - lStartCount
; 
 782 pascal  OSStatus  
MoreProcGetProcessTypeSignature( 
 783     const ProcessSerialNumberPtr pPSN
, 
 784     OSType 
*pProcessType
, 
 787     OSStatus anErr 
= noErr
; 
 788     ProcessInfoRec infoRec
; 
 789     ProcessSerialNumber localPSN
; 
 791     infoRec
.processInfoLength 
= sizeof(ProcessInfoRec
); 
 792     infoRec
.processName 
= NULL
; 
 794     infoRec
.processAppSpec 
= NULL
; 
 799         localPSN
.highLongOfPSN 
= 0; 
 800         localPSN
.lowLongOfPSN  
= kCurrentProcess
; 
 807     anErr 
= GetProcessInformation(&localPSN
, &infoRec
); 
 810         *pProcessType 
= infoRec
.processType
; 
 811         *pCreator 
= infoRec
.processSignature
; 
 819 //  TODO: clean this up, its messy 
 824 #include "wx/mac/corefoundation/cfstring.h" 
 826 #define wxCF_RELEASE true 
 827 #define wxCF_RETAIN  false 
 829 // ---------------------------------------------------------------------------- 
 831 // ---------------------------------------------------------------------------- 
 836     wxCFDictionary(CFTypeRef ref
, bool bRetain 
= wxCF_RELEASE
) 
 838         m_cfmdRef 
= (CFMutableDictionaryRef
) ref
; 
 839         if (bRetain 
== wxCF_RETAIN 
&& ref
) 
 843     wxCFDictionary(CFIndex cfiSize 
= 0) 
 845         CFDictionaryKeyCallBacks kcbs
; 
 846         CFDictionaryValueCallBacks vcbs
; 
 847         BuildKeyCallbacks(&kcbs
); 
 848         BuildValueCallbacks(&vcbs
); 
 850         m_cfmdRef 
= CFDictionaryCreateMutable( 
 851             kCFAllocatorDefault
, cfiSize
, &kcbs
, &vcbs 
); 
 860             CFRelease(m_cfmdRef
); 
 863     static const void* RetainProc(CFAllocatorRef
, const void* v
) 
 864     { return (const void*) CFRetain(v
); } 
 866     static void ReleaseProc(CFAllocatorRef
, const void* v
) 
 869     void MakeMutable(CFIndex cfiSize 
= 0) 
 871         CFDictionaryRef oldref 
= (CFDictionaryRef
) m_cfmdRef
; 
 873         m_cfmdRef 
= CFDictionaryCreateMutableCopy( 
 874             kCFAllocatorDefault
, cfiSize
, oldref 
); 
 879     void BuildKeyCallbacks(CFDictionaryKeyCallBacks
* pCbs
) 
 882         pCbs
->retain 
= RetainProc
; 
 883         pCbs
->release 
= ReleaseProc
; 
 884         pCbs
->copyDescription 
= NULL
; 
 889     void BuildValueCallbacks(CFDictionaryValueCallBacks
* pCbs
) 
 892         pCbs
->retain 
= RetainProc
; 
 893         pCbs
->release 
= ReleaseProc
; 
 894         pCbs
->copyDescription 
= NULL
; 
 898     operator CFTypeRef () const 
 899     { return (CFTypeRef
)m_cfmdRef
; } 
 901     CFDictionaryRef 
GetCFDictionary() const 
 902     { return (CFDictionaryRef
)m_cfmdRef
; } 
 904     CFMutableDictionaryRef 
GetCFMutableDictionary() 
 905     { return (CFMutableDictionaryRef
) m_cfmdRef
; } 
 907     CFTypeRef 
operator [] (CFTypeRef cftEntry
) const 
 910         return (CFTypeRef
) CFDictionaryGetValue((CFDictionaryRef
)m_cfmdRef
, cftEntry
); 
 913     CFIndex 
GetCount() const 
 916         return CFDictionaryGetCount((CFDictionaryRef
)m_cfmdRef
); 
 919     void Add(CFTypeRef cftKey
, CFTypeRef cftValue
) 
 922         wxASSERT(Exists(cftKey
) == false); 
 923         CFDictionaryAddValue(m_cfmdRef
, cftKey
, cftValue
); 
 926     void Remove(CFTypeRef cftKey
) 
 929         wxASSERT(Exists(cftKey
)); 
 930         CFDictionaryRemoveValue(m_cfmdRef
, cftKey
); 
 933     void Set(CFTypeRef cftKey
, CFTypeRef cftValue
) 
 936         wxASSERT(Exists(cftKey
)); 
 937         CFDictionarySetValue(m_cfmdRef
, cftKey
, cftValue
); 
 940     bool Exists(CFTypeRef cftKey
) const 
 943         return CFDictionaryContainsKey((CFDictionaryRef
)m_cfmdRef
, cftKey
); 
 947     { return m_cfmdRef 
!= NULL
; } 
 950     { return IsOk() && CFGetTypeID((CFTypeRef
)m_cfmdRef
) == CFDictionaryGetTypeID(); } 
 952     void PrintOut(wxString
& sMessage
) 
 954         PrintOutDictionary(sMessage
, m_cfmdRef
); 
 957     static void PrintOutDictionary(wxString
& sMessage
, CFDictionaryRef cfdRef
) 
 959         CFIndex cfiCount 
= CFDictionaryGetCount(cfdRef
); 
 960         CFTypeRef
* pKeys 
= new CFTypeRef
[cfiCount
]; 
 961         CFTypeRef
* pValues 
= new CFTypeRef
[cfiCount
]; 
 963         CFDictionaryGetKeysAndValues(cfdRef
, pKeys
, pValues
); 
 965         for (CFIndex i 
= 0; i 
< cfiCount
; ++i
) 
 967             wxString sKey 
= wxMacCFStringHolder(CFCopyTypeIDDescription(CFGetTypeID(pKeys
[i
]))).AsString(); 
 968             wxString sValue 
= wxMacCFStringHolder(CFCopyTypeIDDescription(CFGetTypeID(pValues
[i
]))).AsString(); 
 971                 wxString::Format(wxT("[{#%d} Key : %s]"), (int) i
, 
 974             PrintOutType(sMessage
, sKey
, pKeys
[i
]); 
 977                 wxString::Format(wxT("\n\t[Value : %s]"), 
 980             PrintOutType(sMessage
, sValue
, pValues
[i
]); 
 982             sMessage 
<< wxT("\n"); 
 989     static void PrintOutArray(wxString
& sMessage
, CFArrayRef cfaRef
) 
 991         for (CFIndex i 
= 0; i 
< CFArrayGetCount(cfaRef
); ++i
) 
 993             wxString sValue 
= wxMacCFStringHolder(CFCopyTypeIDDescription(CFGetTypeID( 
 994                 CFArrayGetValueAtIndex(cfaRef
, i
) 
 998                 wxString::Format(wxT("\t\t[{#%d} ArrayValue : %s]\n"), (int) i
, 
1001             PrintOutType(sMessage
, sValue
, CFArrayGetValueAtIndex(cfaRef
, i
)); 
1005     static void PrintOutType(wxString
& sMessage
, const wxString
& sValue
, CFTypeRef cfRef
) 
1007             sMessage 
<< wxT(" {"); 
1009             if (sValue 
== wxT("CFString")) 
1011                  sMessage 
<< wxMacCFStringHolder((CFStringRef
)cfRef
, false).AsString(); 
1013             else if (sValue 
== wxT("CFNumber")) 
1016                 CFNumberGetValue((CFNumberRef
)cfRef
, kCFNumberIntType
, &nOut
); 
1019             else if (sValue 
== wxT("CFDictionary")) 
1021                 PrintOutDictionary(sMessage
, (CFDictionaryRef
)cfRef
); 
1023             else if (sValue 
== wxT("CFArray")) 
1025                 PrintOutArray(sMessage
, (CFArrayRef
)cfRef
); 
1027             else if (sValue 
== wxT("CFBoolean")) 
1029                 sMessage 
<< (cfRef 
== kCFBooleanTrue 
? wxT("true") : wxT("false")); 
1031             else if (sValue 
== wxT("CFURL")) 
1033                 sMessage 
<< wxMacCFStringHolder(CFURLCopyPath((CFURLRef
) cfRef
)).AsString(); 
1037                 sMessage 
<< wxT("*****UNKNOWN TYPE******"); 
1040             sMessage 
<< wxT("} "); 
1044     void MakeValidXML(); 
1047     CFTypeRef 
WriteAsXML() 
1049         return CFPropertyListCreateXMLData(kCFAllocatorDefault
, m_cfmdRef
); 
1052     bool ReadAsXML(CFTypeRef cfData
, wxString
* pErrorMsg 
= NULL
) 
1055         CFStringRef cfsError
=NULL
; 
1056         m_cfmdRef 
= (CFMutableDictionaryRef
) CFPropertyListCreateFromXMLData( 
1057                     kCFAllocatorDefault
, 
1059                     kCFPropertyListMutableContainersAndLeaves
, 
1064                 *pErrorMsg 
= wxMacCFStringHolder(cfsError
).AsString(); 
1066                 CFRelease(cfsError
); 
1069         return m_cfmdRef 
!= NULL
; 
1073     CFMutableDictionaryRef m_cfmdRef
; 
1076 // ---------------------------------------------------------------------------- 
1078 // ---------------------------------------------------------------------------- 
1083     wxCFArray(CFTypeRef ref
, bool bRetain 
= wxCF_RELEASE
) 
1085         m_cfmaRef 
= (CFMutableArrayRef
)ref
; 
1086         if (bRetain 
== wxCF_RETAIN 
&& ref
) 
1090     wxCFArray(CFIndex cfiSize 
= 0) : m_cfmaRef(NULL
) 
1091     { Create(cfiSize
); } 
1096     void MakeMutable(CFIndex cfiSize 
= 0) 
1098         wxASSERT(IsValid()); 
1100         CFMutableArrayRef oldref 
= m_cfmaRef
; 
1101         m_cfmaRef 
= CFArrayCreateMutableCopy( 
1102                 kCFAllocatorDefault
, 
1104                 (CFArrayRef
)oldref
); 
1108     void BuildCallbacks(CFArrayCallBacks
* pCbs
) 
1111         pCbs
->retain 
= RetainProc
; 
1112         pCbs
->release 
= ReleaseProc
; 
1113         pCbs
->copyDescription 
= NULL
; 
1117     void Create(CFIndex cfiSize 
= 0) 
1120         CFArrayCallBacks cb
; 
1121         BuildCallbacks(&cb
); 
1123         m_cfmaRef 
= CFArrayCreateMutable(kCFAllocatorDefault
, cfiSize
, &cb
); 
1127     { if (m_cfmaRef
) CFRelease(m_cfmaRef
); } 
1129     static const void* RetainProc(CFAllocatorRef
, const void* v
) 
1130     { return (const void*) CFRetain(v
); } 
1132     static void ReleaseProc(CFAllocatorRef
, const void* v
) 
1135     operator CFTypeRef () const 
1136     { return (CFTypeRef
)m_cfmaRef
; } 
1138     CFArrayRef 
GetCFArray() const 
1139     { return (CFArrayRef
)m_cfmaRef
; } 
1141     CFMutableArrayRef 
GetCFMutableArray() 
1142     { return (CFMutableArrayRef
) m_cfmaRef
; } 
1144     CFTypeRef 
operator [] (CFIndex cfiIndex
) const 
1146         wxASSERT(IsValid()); 
1147         return (CFTypeRef
) CFArrayGetValueAtIndex((CFArrayRef
)m_cfmaRef
, cfiIndex
); 
1152         wxASSERT(IsValid()); 
1153         return CFArrayGetCount((CFArrayRef
)m_cfmaRef
); 
1156     void Add(CFTypeRef cftValue
) 
1158         wxASSERT(IsValid()); 
1159         CFArrayAppendValue(m_cfmaRef
, cftValue
); 
1162     void Remove(CFIndex cfiIndex
) 
1164         wxASSERT(IsValid()); 
1165         wxASSERT(cfiIndex 
< GetCount()); 
1166         CFArrayRemoveValueAtIndex(m_cfmaRef
, cfiIndex
); 
1169     void Set(CFIndex cfiIndex
, CFTypeRef cftValue
) 
1171         wxASSERT(IsValid()); 
1172         wxASSERT(cfiIndex 
< GetCount()); 
1173         CFArraySetValueAtIndex(m_cfmaRef
, cfiIndex
, cftValue
); 
1177     { return m_cfmaRef 
!= NULL
; } 
1179     bool IsValid() const 
1181         return IsOk() && CFGetTypeID((CFTypeRef
)m_cfmaRef
) == CFArrayGetTypeID(); 
1185     void MakeValidXML(); 
1189     CFMutableArrayRef m_cfmaRef
; 
1192 // ---------------------------------------------------------------------------- 
1194 // ---------------------------------------------------------------------------- 
1199     wxCFString(CFTypeRef ref
, bool bRetain 
= wxCF_RELEASE
) : m_Holder((CFStringRef
)ref
, bRetain 
== wxCF_RELEASE
) 
1202     wxCFString(const wxChar
* szString
) : m_Holder(wxString(szString
), wxLocale::GetSystemEncoding()) 
1205     wxCFString(const wxString
& sString
) : m_Holder(sString
, wxLocale::GetSystemEncoding()) 
1208     virtual ~wxCFString() {} 
1210     operator CFTypeRef() const 
1211     { return (CFTypeRef
) ((CFStringRef
) m_Holder
); } 
1214     { return ((CFTypeRef
)(*this)) != NULL
; } 
1216     wxString 
BuildWXString() 
1217     { return m_Holder
.AsString(); } 
1220     wxMacCFStringHolder m_Holder
; 
1223 // ---------------------------------------------------------------------------- 
1225 // ---------------------------------------------------------------------------- 
1230     wxCFNumber(int nValue
) 
1232         m_cfnRef 
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &nValue
); 
1235     wxCFNumber(CFTypeRef ref
, bool bRetain 
= wxCF_RELEASE
) : m_cfnRef((CFNumberRef
)ref
) 
1237         if (bRetain 
== wxCF_RETAIN 
&& ref
) 
1241     virtual ~wxCFNumber() 
1244             CFRelease(m_cfnRef
); 
1247     operator CFTypeRef() const 
1248     { return (CFTypeRef
) m_cfnRef
; } 
1253         CFNumberGetValue( m_cfnRef
, kCFNumberIntType
, &nOut 
); 
1259     { return m_cfnRef 
!= NULL
; } 
1262     CFNumberRef m_cfnRef
; 
1265 // ---------------------------------------------------------------------------- 
1267 // ---------------------------------------------------------------------------- 
1272     wxCFURL(CFTypeRef ref 
= NULL
, bool bRetain 
= wxCF_RELEASE
) : m_cfurlRef((CFURLRef
)ref
) 
1274         if (bRetain 
== wxCF_RETAIN 
&& ref
) 
1278     wxCFURL(const wxCFString
& URLString
, CFTypeRef BaseURL 
= NULL
) 
1280         Create(URLString
, BaseURL
); 
1283     void Create(const wxCFString
& URLString
, CFTypeRef BaseURL 
= NULL
) 
1285         m_cfurlRef 
= CFURLCreateWithString( 
1286             kCFAllocatorDefault
, 
1287             (CFStringRef
)(CFTypeRef
)URLString
, 
1288             (CFURLRef
) BaseURL
); 
1294             CFRelease(m_cfurlRef
); 
1297     wxString 
BuildWXString() 
1299         return wxCFString(CFURLCopyPath(m_cfurlRef
)).BuildWXString(); 
1302     operator CFTypeRef() const 
1303     { return (CFTypeRef
)m_cfurlRef
; } 
1306     { return m_cfurlRef 
!= NULL
; } 
1309     CFURLRef m_cfurlRef
; 
1312 // ---------------------------------------------------------------------------- 
1314 // ---------------------------------------------------------------------------- 
1316 #define wxCFDATA_RELEASEBUFFER  1 
1321     wxCFData(CFTypeRef ref
, bool bRetain 
= wxCF_RELEASE
) : m_cfdaRef((CFDataRef
)ref
) 
1323         if (bRetain 
== wxCF_RETAIN 
&& ref
) 
1327     wxCFData(const UInt8
* pBytes
, CFIndex len
, bool bKeep 
= wxCFDATA_RELEASEBUFFER
) 
1329         if (bKeep 
== wxCFDATA_RELEASEBUFFER
) 
1331             m_cfdaRef 
= CFDataCreateWithBytesNoCopy
 
1332                             (kCFAllocatorDefault
, pBytes
, len
, kCFAllocatorDefault
); 
1336             m_cfdaRef 
= CFDataCreate(kCFAllocatorDefault
, pBytes
, len
); 
1343             CFRelease(m_cfdaRef
); 
1346     const UInt8
* GetValue() 
1347     { return CFDataGetBytePtr(m_cfdaRef
); } 
1350     { return CFDataGetLength(m_cfdaRef
); } 
1352     operator CFTypeRef() const 
1353     { return (CFTypeRef
)m_cfdaRef
; } 
1356     { return m_cfdaRef 
!= NULL
; } 
1359     CFDataRef m_cfdaRef
; 
1362 void wxCFDictionary::MakeValidXML() 
1364         CFIndex cfiCount 
= GetCount(); 
1365         CFTypeRef
* pKeys 
= new CFTypeRef
[cfiCount
]; 
1366         CFTypeRef
* pValues 
= new CFTypeRef
[cfiCount
]; 
1368         CFDictionaryGetKeysAndValues(m_cfmdRef
, pKeys
, pValues
); 
1370         // for plist xml format, all dictionary keys must be cfstrings and 
1371         // no values in the dictionary or subkeys/values can be NULL; 
1372         // additionally, CFURLs are not allowed 
1373         for (CFIndex i 
= 0; i 
< cfiCount
; ++i
) 
1375             // must be an array, dictionary, string, bool, or int and cannot be null 
1376             // and dictionaries can only contain cfstring keys 
1377             CFTypeRef cfRef 
= pValues
[i
]; 
1379                 CFGetTypeID(pKeys
[i
]) != CFStringGetTypeID() || 
1387                 pKeys 
= new CFTypeRef
[cfiCount
]; 
1388                 pValues 
= new CFTypeRef
[cfiCount
]; 
1389                 CFDictionaryGetKeysAndValues(m_cfmdRef
, pKeys
, pValues
); 
1391             else if (CFGetTypeID(cfRef
) == CFArrayGetTypeID()) 
1394                 wxCFArray 
cfaCurrent(cfRef
); 
1395                 cfaCurrent
.MakeMutable(); 
1396                 cfaCurrent
.MakeValidXML(); 
1397                 Set(pKeys
[i
], cfaCurrent
); 
1399             else if (CFGetTypeID(cfRef
) == CFDictionaryGetTypeID()) 
1402                 wxCFDictionary 
cfdCurrent(cfRef
); 
1403                 cfdCurrent
.MakeMutable(); 
1404                 cfdCurrent
.MakeValidXML(); 
1405                 Set(pKeys
[i
], cfdCurrent
); 
1407             else if ( CFGetTypeID(cfRef
) != CFStringGetTypeID() && 
1408                       CFGetTypeID(cfRef
) != CFNumberGetTypeID() && 
1409                       CFGetTypeID(cfRef
) != CFBooleanGetTypeID() ) 
1416                 pKeys 
= new CFTypeRef
[cfiCount
]; 
1417                 pValues 
= new CFTypeRef
[cfiCount
]; 
1418                 CFDictionaryGetKeysAndValues(m_cfmdRef
, pKeys
, pValues
); 
1426 void wxCFArray::MakeValidXML() 
1428         for (CFIndex i 
= 0; i 
< GetCount(); ++i
) 
1430             //must be an array, dictionary, string, bool, or int and cannot be null 
1431             //and dictionaries can only contain cfstring keys 
1432             CFTypeRef cfRef 
= (*this)[i
]; 
1438             else if (CFGetTypeID(cfRef
) == CFArrayGetTypeID()) 
1441                 wxCFArray 
cfaCurrent(cfRef
); 
1442                 cfaCurrent
.MakeMutable(); 
1443                 cfaCurrent
.MakeValidXML(); 
1446             else if (CFGetTypeID(cfRef
) == CFDictionaryGetTypeID()) 
1449                 wxCFDictionary 
cfdCurrent(cfRef
); 
1450                 cfdCurrent
.MakeMutable(); 
1451                 cfdCurrent
.MakeValidXML(); 
1454             else if ( CFGetTypeID(cfRef
) != CFStringGetTypeID() && 
1455                       CFGetTypeID(cfRef
) != CFNumberGetTypeID() && 
1456                       CFGetTypeID(cfRef
) != CFBooleanGetTypeID() ) 
1472 wxFileType
* wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo
& ftInfo
) 
1474     bool bInfoSuccess 
= false; 
1476     const wxArrayString
& asExtensions 
= ftInfo
.GetExtensions(); 
1477     size_t dwFoundIndex 
= 0; 
1478     if (!asExtensions
.GetCount()) 
1480         wxLogDebug(wxT("Must have extension to associate with")); 
1483     // Find and write to Info.plist in main bundle (note that some other 
1484     // apps have theirs named differently, i.e. IE's is named Info-macos.plist 
1485     // some apps (non-wx) use the 'plst' resource instead 
1486     CFBundleRef cfbMain 
= CFBundleGetMainBundle(); 
1489         UInt32 dwBundleType
, dwBundleCreator
; 
1490         CFBundleGetPackageInfo(cfbMain
, &dwBundleType
, &dwBundleCreator
); 
1492         // if launching terminal non-app, version will be 'BNDL' (generic bundle, maybe in other cases too), 
1493         // which will give us the incorrect info.plist path 
1494         // otherwise it will be 'APPL', or in the case of a framework, 'FMWK' 
1495         if (dwBundleType 
== 'APPL') 
1497             wxCFURL 
cfurlBundleLoc((CFTypeRef
)CFBundleCopyBundleURL(cfbMain
)); 
1498 //             wxCFURL cfurlBundleLoc((CFTypeRef)CFBundleCopyExecutableURL(cfbMain)); 
1500 //            sInfoPath << wxT("file://"); 
1501             sInfoPath 
<< cfurlBundleLoc
.BuildWXString(); 
1502             sInfoPath 
<< wxT("Contents/Info.plist"); 
1504 //        wxCFDictionary cfdInfo( CFBundleGetInfoDictionary(cfbMain), wxCF_RETAIN ); 
1505             wxCFDictionary cfdInfo
; 
1506             bool bInfoOpenSuccess 
= false; 
1508             if (indictfile
.Open(sInfoPath
, wxFile::read
)) 
1510                 CFIndex cfiBufLen 
= (CFIndex
) indictfile
.Length(); 
1511                 const UInt8
* pBuffer 
= new UInt8
[cfiBufLen
]; 
1512                 indictfile
.Read((void*)pBuffer
, cfiBufLen
); 
1513                 wxCFData 
cfdaInDict(pBuffer
, cfiBufLen
); 
1515                 bInfoOpenSuccess 
= cfdInfo
.ReadAsXML(cfdaInDict
, &sError
); 
1516                 if (!bInfoOpenSuccess
) 
1521             if (bInfoOpenSuccess
) 
1523                 cfdInfo
.MakeMutable( cfdInfo
.GetCount() + 1 ); 
1525                 wxCFArray 
cfaDocTypes( cfdInfo
[ wxCFString(wxT("CFBundleDocumentTypes")) ], wxCF_RETAIN 
); 
1527                 bool bAddDocTypesArrayToDictionary 
= !cfaDocTypes
.IsOk(); 
1528                 if (bAddDocTypesArrayToDictionary
) 
1529                     cfaDocTypes
.Create(); 
1531                     cfaDocTypes
.MakeMutable( cfaDocTypes
.GetCount() + 1 ); 
1533                 bool bEntryFound 
= false; 
1535                 // search for duplicates 
1537                 for (i 
= 0; i 
< cfaDocTypes
.GetCount(); ++i
) 
1539                     wxCFDictionary 
cfdDocTypeEntry( cfaDocTypes
[i
], wxCF_RETAIN 
); 
1541                     // A lot of apps don't support MIME types for some reason 
1542                     // so we go by extensions only 
1543                     wxCFArray 
cfaExtensions( cfdDocTypeEntry
[ wxCFString(wxT("CFBundleTypeExtensions")) ], 
1546                     if (!cfaExtensions
.IsOk()) 
1549                     for (CFIndex iExt 
= 0; iExt 
< cfaExtensions
.GetCount(); ++iExt
) 
1551                         for (size_t iWXExt 
= 0; iWXExt 
< asExtensions
.GetCount(); ++iWXExt
) 
1553                             if (asExtensions
[iWXExt
] == 
1554                                     wxCFString(cfaExtensions
[iExt
], wxCF_RETAIN
).BuildWXString()) 
1557                                 dwFoundIndex 
= iWXExt
; 
1561                         } //end of wxstring array 
1565                     } //end for cf array 
1569                 } //end for doctypes 
1571                 wxCFDictionary cfdNewEntry
; 
1573                 if (!ftInfo
.GetDescription().empty()) 
1575                     cfdNewEntry
.Add( wxCFString(wxT("CFBundleTypeName")), 
1576                                 wxCFString(ftInfo
.GetDescription()) ); 
1579                 if (!ftInfo
.GetIconFile().empty()) 
1581                     cfdNewEntry
.Add( wxCFString(wxT("CFBundleTypeIconFile")), 
1582                                     wxCFString(ftInfo
.GetIconFile()) ); 
1585                 wxCFArray cfaOSTypes
; 
1586                 wxCFArray cfaExtensions
; 
1587                 wxCFArray cfaMimeTypes
; 
1589                 //OSTypes is a cfarray of four-char-codes - '****' for unrestricted 
1590                 cfaOSTypes
.Add( wxCFString(wxT("****")) ); 
1591                 cfdNewEntry
.Add( wxCFString(wxT("CFBundleTypeOSTypes")), cfaOSTypes 
); 
1593                 //'*' for unrestricted 
1594                 if (ftInfo
.GetExtensionsCount() != 0) 
1596                     for (size_t iExtension 
= 0; iExtension 
< ftInfo
.GetExtensionsCount(); ++iExtension
) 
1598                         cfaExtensions
.Add( wxCFString( asExtensions
[iExtension
] ) ); 
1601                     cfdNewEntry
.Add( wxCFString(wxT("CFBundleTypeExtensions")), cfaExtensions 
); 
1604                 if (!ftInfo
.GetMimeType().empty()) 
1606                     cfaMimeTypes
.Add( wxCFString(ftInfo
.GetMimeType()) ); 
1607                     cfdNewEntry
.Add( wxCFString(wxT("CFBundleTypeMIMETypes")), cfaMimeTypes 
); 
1610                 // Editor - can perform all actions 
1611                 // Viewer - all actions except manipulation/saving 
1612                 // None - can perform no actions 
1613                 cfdNewEntry
.Add( wxCFString(wxT("CFBundleTypeRole")), wxCFString(wxT("Editor")) ); 
1615                 // Is application bundled? 
1616                 cfdNewEntry
.Add( wxCFString(wxT("LSTypeIsPackage")), kCFBooleanTrue 
); 
1619                     cfaDocTypes
.Set(i
, cfdNewEntry
); 
1621                     cfaDocTypes
.Add(cfdNewEntry
); 
1623                 // set the doc types array in the muted dictionary 
1624                 if (bAddDocTypesArrayToDictionary
) 
1625                     cfdInfo
.Add(wxCFString(wxT("CFBundleDocumentTypes")), cfaDocTypes
); 
1627                     cfdInfo
.Set(wxCFString(wxT("CFBundleDocumentTypes")), cfaDocTypes
); 
1629                 cfdInfo
.MakeValidXML(); 
1632                 if (outdictfile
.Open(sInfoPath
, wxFile::write
)) 
1634                     wxCFData 
cfdaInfo(cfdInfo
.WriteAsXML()); 
1635                     if (cfdaInfo
.IsOk()) 
1637                         if (outdictfile
.Write(cfdaInfo
.GetValue(), cfdaInfo
.GetCount()) != 
1638                             (wxFileOffset
)cfdaInfo
.GetCount()) 
1640                             wxLogDebug(wxT("error in writing to file")); 
1644                             bInfoSuccess 
= true; 
1646 //#if defined(__DARWIN__) 
1647 //                //force launch services to update its database for the finder 
1648 //                OSStatus status = LSRegisterURL((CFURLRef)(CFTypeRef)cfurlBundleLoc, true); 
1649 //                if (status != noErr) 
1651 //                    wxLogDebug(wxT("LSRegisterURL Failed.")); 
1655                         outdictfile
.Close(); 
1659                         outdictfile
.Close(); 
1660                         wxLogDebug(wxT("Could not read in new dictionary")); 
1665                     wxLogDebug(wxString(wxT("Could not open [")) + 
1666                     sInfoPath 
+ wxT("] for writing.")); 
1671                 wxLogDebug(wxT("No info dictionary in main bundle")); 
1676             wxLogDebug(wxT("Can only call associate from bundled app within XXX.app")); 
1681         wxLogDebug(wxT("No main bundle")); 
1684 #if defined(__DARWIN__) 
1689     // on mac you have to embed it into the mac's file reference resource ('FREF' I believe) 
1690     // or, alternately, you could just add an entry to m_hDatabase, but you'd need to get 
1691     // the app's signature somehow... 
1693     OSType processType
, creator
; 
1694     OSStatus status 
= MoreProcGetProcessTypeSignature(NULL
, &processType
, &creator
); 
1696     if (status 
== noErr
) 
1698         Str255 psCreatorName
; 
1701         status 
= FindApplication(creator
, false, psCreatorName
, &dummySpec
); 
1704         status 
= LSFindApplicationForInfo( creator
, NULL
, NULL
, &fsref 
,NULL
); 
1706         status 
= FSGetCatalogInfo(&fsref
, kFSCatInfoNone
, NULL
, &name
, NULL
, NULL
); 
1707         CFStringRef str 
= FSCreateStringFromHFSUniStr( 0 , &name 
); 
1708         CFStringGetPascalString(str
, psCreatorName
, 256, CFStringGetSystemEncoding()); 
1712         if (status 
== noErr
) 
1714             //get the file type if it exists - 
1715             //if it really does then modify the database then save it, 
1716             //otherwise we need to create a whole new entry 
1717             wxFileType
* pFileType 
= GetFileTypeFromExtension(asExtensions
[dwFoundIndex
]); 
1721                 ICGetMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, 
1722                     pFileType
->m_impl
->m_lIndex
, &entry 
); 
1724                 memcpy(entry
.creatorAppName
, psCreatorName
, sizeof(Str255
)); 
1725                 entry
.fileCreator 
= creator
; 
1727                 status 
= ICSetMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, 
1728                     pFileType
->m_impl
->m_lIndex
, &entry 
); 
1731                 if (status 
== noErr
) 
1735                     //kICAttrNoChange means we don't care about attributes such as 
1736                     //locking in the database 
1737 //                    status = ICSetPrefHandle((ICInstance) m_hIC, kICMapping, 
1738 //                                             kICAttrNoChange, (Handle) m_hDatabase); 
1739 //                    if (status == noErr) 
1740 //                        return pFileType; 
1743 //                        wxLogDebug(wxString::Format(wxT("%i - %s"), (int)status, wxT("ICSetPrefHandle failed."))); 
1748                     wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICSetMapEntry failed."))); 
1751                 // failure - cleanup 
1756                 // TODO: Maybe force all 3 of these to be non-empty? 
1757                 Str255 psExtension
, psMimeType
, psDescription
; 
1759                 wxMacStringToPascal(wxString(wxT(".")) + ftInfo
.GetExtensions()[0], psExtension
); 
1760                 wxMacStringToPascal(ftInfo
.GetMimeType(), psMimeType
); 
1761                 wxMacStringToPascal(ftInfo
.GetDescription(), psDescription
); 
1763                 Str255 psPostCreatorName
; 
1764                 wxMacStringToPascal(wxEmptyString
, psPostCreatorName
); 
1766                 //add the entry to the database 
1768                 entry
.totalLength 
= sizeof(ICMapEntry
); 
1769                 entry
.fixedLength 
= kICMapFixedLength
; 
1771                 entry
.fileType 
= 0; //TODO:  File type? 
1772                 entry
.fileCreator 
= creator
; 
1773                 entry
.postCreator 
= 0; 
1774                 entry
.flags 
= kICMapDataForkBit
; //TODO:  Maybe resource is valid by default too? 
1775                 PLstrcpy( entry
.extension 
, psExtension 
) ; 
1776                 memcpy(entry
.creatorAppName
, psCreatorName
, sizeof(Str255
)); 
1777                 memcpy(entry
.postAppName
, psPostCreatorName
, sizeof(Str255
)); 
1778                 memcpy(entry
.MIMEType
, psMimeType
, sizeof(Str255
)); 
1779                 memcpy(entry
.entryName
, psDescription
, sizeof(Str255
)); 
1781                 status 
= ICAddMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, &entry
); 
1782                 if (status 
== noErr
) 
1784                     return GetFileTypeFromExtension(ftInfo
.GetMimeType()); 
1786 //                    kICAttrNoChange means we don't care about attributes such as 
1787 //                    locking in the database 
1788 //                    status = ICSetPrefHandle((ICInstance) m_hIC, kICMapping, 
1789 //                                             kICAttrNoChange, (Handle) m_hDatabase); 
1791                     // return the entry in the database if successful 
1792 //                    if (status == noErr) 
1793 //                        return GetFileTypeFromExtension(ftInfo.GetMimeType()); 
1796 //                        wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICSetPrefHandle failed."))); 
1801                     wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICAppMapEntry failed."))); 
1804         } // end if FindApplcation was successful 
1807             wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("FindApplication failed."))); 
1809     } // end if it could obtain app's signature 
1812         wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("GetProcessSignature failed."))); 
1819 wxMimeTypesManagerImpl::Unassociate(wxFileType 
*pFileType
) 
1821     wxASSERT(pFileType
); 
1822     bool bInfoSuccess 
= false; 
1824     wxArrayString asExtensions
; 
1825     pFileType
->GetExtensions(asExtensions
); 
1827     if (!asExtensions
.GetCount()) 
1829         wxLogDebug(wxT("Must have extension to disassociate")); 
1833     // Find and write to Info.plist in main bundle (note that some other 
1834     // apps have theirs named differently, i.e. IE's is named Info-macos.plist 
1835     // some apps (non-wx) use the 'plst' resource instead 
1836     CFBundleRef cfbMain 
= CFBundleGetMainBundle(); 
1839         UInt32 dwBundleType
, dwBundleCreator
; 
1840         CFBundleGetPackageInfo(cfbMain
, &dwBundleType
, &dwBundleCreator
); 
1842         // if launching terminal non-app, version will be 'BNDL' (generic bundle, maybe in other cases too), 
1843         // which will give us the incorrect info.plist path 
1844         // otherwise it will be 'APPL', or in the case of a framework, 'FMWK' 
1845         if (dwBundleType 
== 'APPL') 
1848             wxCFURL 
cfurlBundleLoc((CFTypeRef
)CFBundleCopyBundleURL(cfbMain
)); 
1849 //             wxCFURL cfurlBundleLoc((CFTypeRef)CFBundleCopyExecutableURL(cfbMain)); 
1851 //            sInfoPath << wxT("file://"); 
1852             sInfoPath 
<< cfurlBundleLoc
.BuildWXString(); 
1853             sInfoPath 
<< wxT("Contents/Info.plist"); 
1855 //        wxCFDictionary cfdInfo( (CFTypeRef) CFBundleGetInfoDictionary(cfbMain), wxCF_RETAIN ); 
1856             wxCFDictionary cfdInfo
; 
1857             bool bInfoOpenSuccess 
= false; 
1859             if (indictfile
.Open(sInfoPath
, wxFile::read
)) 
1861                 CFIndex cfiBufLen 
= (CFIndex
) indictfile
.Length(); 
1862                 const UInt8
* pBuffer 
= new UInt8
[cfiBufLen
]; 
1863                 indictfile
.Read((void*)pBuffer
, cfiBufLen
); 
1864                 wxCFData 
cfdaInDict(pBuffer
, cfiBufLen
); 
1866                 bInfoOpenSuccess 
= cfdInfo
.ReadAsXML(cfdaInDict
, &sError
); 
1867                 if (!bInfoOpenSuccess
) 
1872             if (bInfoOpenSuccess
) 
1874                 cfdInfo
.MakeMutable( cfdInfo
.GetCount() + 1 ); 
1876                 wxCFArray 
cfaDocTypes( cfdInfo
[ wxCFString(wxT("CFBundleDocumentTypes")) ], wxCF_RETAIN 
); 
1878                 if (cfaDocTypes
.IsOk()) 
1880                     bool bEntryFound 
= false; 
1882                     //search for duplicate 
1884                     for (i 
= 0; i 
< cfaDocTypes
.GetCount(); ++i
) 
1886                         wxCFDictionary 
cfdDocTypeEntry( cfaDocTypes
[i
], wxCF_RETAIN 
); 
1888                         //A lot of apps dont do to mime types for some reason 
1889                         //so we go by extensions only 
1890                         wxCFArray 
cfaExtensions( cfdDocTypeEntry
[ wxCFString(wxT("CFBundleTypeExtensions")) ], 
1893                         if (!cfaExtensions
.IsOk()) 
1896                         for (CFIndex iExt 
= 0; iExt 
< cfaExtensions
.GetCount(); ++iExt
) 
1898                             for (size_t iWXExt 
= 0; iWXExt 
< asExtensions
.GetCount(); ++iWXExt
) 
1900                                 if (asExtensions
[iWXExt
] == 
1901                                     wxCFString(cfaExtensions
[iExt
], wxCF_RETAIN
).BuildWXString()) 
1904                                     cfaDocTypes
.Remove(i
); 
1905                                     cfdInfo
.Set( wxCFString(wxT("CFBundleDocumentTypes")) , cfaDocTypes 
); 
1908                             } //end of wxstring array 
1912                         } //end for cf array 
1920                         cfdInfo
.MakeValidXML(); 
1923                         if (outdictfile
.Open(sInfoPath
, wxFile::write
)) 
1925                             wxCFData 
cfdaInfo(cfdInfo
.WriteAsXML()); 
1926                             if (cfdaInfo
.IsOk()) 
1928                                 if (outdictfile
.Write(cfdaInfo
.GetValue(), cfdaInfo
.GetCount()) != 
1929                                     (wxFileOffset
)cfdaInfo
.GetCount()) 
1931                                     wxLogDebug(wxT("error in writing to file")); 
1935                                     bInfoSuccess 
= true; 
1937 //#if defined(__DARWIN__) 
1938 //                //force launch services to update its database for the finder 
1939 //                OSStatus status = LSRegisterURL((CFURLRef)(CFTypeRef)cfurlBundleLoc, true); 
1940 //                if (status != noErr) 
1942 //                    wxLogDebug(wxT("LSRegisterURL Failed.")); 
1946                                 outdictfile
.Close(); 
1950                                 outdictfile
.Close(); 
1951                                 wxLogDebug(wxT("Could not read in new dictionary")); 
1957                                 wxString(wxT("Could not open [")) + 
1958                                 sInfoPath 
+ wxT("] for writing.")); 
1963                         wxLogDebug(wxT("Entry not found to remove")); 
1966                         wxCFDictionary::PrintOutArray(sPrintOut
, (CFArrayRef
)(CFTypeRef
)cfaDocTypes
); 
1967                         wxLogDebug(sPrintOut
); 
1969                         for (size_t i 
= 0; i 
< asExtensions
.GetCount(); ++i
) 
1970                             wxLogDebug(asExtensions
[i
]); 
1975                     wxLogDebug(wxT("No doc types array found")); 
1976                     wxString sPrintOut
;  cfdInfo
.PrintOut(sPrintOut
);  wxLogDebug(sPrintOut
); 
1981                 wxLogDebug(wxT("No info dictionary in main bundle")); 
1986             wxLogDebug(wxT("Can only call associate from bundled app within XXX.app")); 
1991         wxLogDebug(wxT("No main bundle")); 
1994 #if defined(__DARWIN__) 
1999     // this should be as easy as removing the entry from the database 
2000     // and then saving the database 
2001     OSStatus status 
= ICDeleteMapEntry( (ICInstance
) m_hIC
, (Handle
) m_hDatabase
, 
2002                             pFileType
->m_impl
->m_lIndex
); 
2004     if (status 
== noErr
) 
2008         //kICAttrNoChange means we don't care about attributes such as 
2009         //locking in the database 
2010 //        status = ICSetPrefHandle((ICInstance) m_hIC, kICMapping, 
2011 //                    kICAttrNoChange, (Handle) m_hDatabase); 
2013 //        if (status == noErr) 
2019 //            wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICSetPrefHandle failed."))); 
2024         wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__
, wxT("ICDeleteMapEntry failed."))); 
2031     CFWriteStreamRef cfwsInfo 
= CFWriteStreamCreateWithFile( 
2032            kCFAllocatorDefault
, 
2033            (CFURLRef
) (CFTypeRef
)cfurlInfoLoc 
); 
2038             Boolean bOpened 
= CFWriteStreamOpen(cfwsInfo
); 
2041                 CFStringRef cfsError
; 
2042                 CFIndex cfiWritten 
= CFPropertyListWriteToStream((CFPropertyListRef
)(CFTypeRef
)cfdInfo
, 
2044                                     kCFPropertyListXMLFormat_v1_0
, //100 
2046                 if (cfsError 
&& cfiWritten 
== 0) 
2048                     wxLogDebug(wxCFString(cfsError
).BuildWXString()); 
2050                     cfdInfo
.PrintOut(sMessage
); 
2051                     wxLogDebug(sMessage
); 
2055                     bInfoSuccess 
= true; 
2056 //#if defined(__DARWIN__) 
2057 //                //force launch services to update its database for the finder 
2058 //                OSStatus status = LSRegisterURL((CFURLRef)(CFTypeRef)cfurlBundleLoc, true); 
2059 //                if (status != noErr) 
2061 //                    wxLogDebug(wxT("LSRegisterURL Failed.")); 
2066                 CFWriteStreamClose(cfwsInfo
); 
2069 #endif //wxUSE_MIMETYPE