]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/mimetmac.cpp
must be static of course, otherwise items just get appended for every menu-build
[wxWidgets.git] / src / mac / carbon / mimetmac.cpp
CommitLineData
7dc3cc31
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: mac/mimetype.cpp
c9e227f4
RN
3// Purpose: Mac Carbon implementation for wx mime-related classes
4// Author: Ryan Norton
7dc3cc31 5// Modified by:
c9e227f4 6// Created: 04/16/2005
7dc3cc31 7// RCS-ID: $Id$
c9e227f4
RN
8// Copyright: (c) 2005 Ryan Norton (<wxprojects@comcast.net>)
9// Licence: wxWindows licence
7dc3cc31
VS
10/////////////////////////////////////////////////////////////////////////////
11
5af840f1
RN
12//
13//
14// TODO: Search Info[-macos](classic).plist dictionary in addition
15// to Internet Config database.
16//
17// Maybe try a brainstorm a way to change the wxMimeTypesManager API
18// to get info from a file instead/addition to current get all stuff
19// API so that we can use Launch Services to get mime type info.
20//
21// Implement geticon from one of the finder info functions - or
22// use launch services and search that app's plist for the icon.
23//
24// Put some special juice in for the print command.
25//
26//
27//
28
3d1a4878 29#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
7dc3cc31
VS
30#pragma implementation "mimetype.h"
31#endif
32
33// for compilers that support precompilation, includes "wx.h".
34#include "wx/wxprec.h"
35
36#ifdef __BORLANDC__
37 #pragma hdrstop
38#endif
39
7dc3cc31
VS
40#ifndef WX_PRECOMP
41 #include "wx/string.h"
42 #if wxUSE_GUI
43 #include "wx/icon.h"
44 #endif
45#endif //WX_PRECOMP
46
47
4b8f9d46
RN
48#if wxUSE_MIMETYPE
49
7dc3cc31
VS
50#include "wx/log.h"
51#include "wx/file.h"
52#include "wx/intl.h"
53#include "wx/dynarray.h"
54#include "wx/confbase.h"
55
56#include "wx/mac/mimetype.h"
c9e227f4 57#include "wx/mac/private.h" //wxMacMakeStringFromPascal
7dc3cc31
VS
58
59// other standard headers
60#include <ctype.h>
c9e227f4
RN
61#include <InternetConfig.h> //For mime types
62
7dc3cc31 63
c9e227f4
RN
64/* START CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html) */
65
66 /* IsRemoteVolume can be used to find out if the
67 volume referred to by vRefNum is a remote volume
68 located somewhere on a network. the volume's attribute
69 flags (copied from the GetVolParmsInfoBuffer structure)
70 are returned in the longword pointed to by vMAttrib. */
71OSErr IsRemoteVolume(short vRefNum, Boolean *isRemote, long *vMAttrib) {
72 HParamBlockRec volPB;
73 GetVolParmsInfoBuffer volinfo;
74 OSErr err;
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);
80 if (err == noErr) {
81 *isRemote = (volinfo.vMServerAdr != 0);
82 *vMAttrib = volinfo.vMAttrib;
83 }
84 return err;
85}
86
87
88 /* BuildVolumeList fills the array pointed to by vols with
89 a list of the currently mounted volumes. If includeRemote
90 is true, then remote server volumes will be included in
91 the list. When remote server volumes are included in the
92 list, they will be added to the end of the list. On entry,
93 *count should contain the size of the array pointed to by
94 vols. On exit, *count will be set to the number of id numbers
95 placed in the array. If vMAttribMask is non-zero, then
96 only volumes with matching attributes are added to the
97 list of volumes. bits in the vMAttribMask should use the
98 same encoding as bits in the vMAttrib field of
99 the GetVolParmsInfoBuffer structure. */
100OSErr BuildVolumeList(Boolean includeRemote, short *vols,
101 long *count, long vMAttribMask) {
102 HParamBlockRec volPB;
103 Boolean isRemote;
104 OSErr err;
105 long nlocal, nremote;
106 long vMAttrib;
107
108 /* set up and check parameters */
109 volPB.volumeParam.ioNamePtr = NULL;
110 nlocal = nremote = 0;
111 if (*count == 0) return noErr;
112
113 /* iterate through volumes */
114 for (volPB.volumeParam.ioVolIndex = 1;
115 PBHGetVInfoSync(&volPB) == noErr;
116 volPB.volumeParam.ioVolIndex++) {
117
118 /* skip remote volumes, if necessary */
119 err = IsRemoteVolume(volPB.volumeParam.ioVRefNum, &isRemote, &vMAttrib);
120 if (err != noErr) goto bail;
121 if ( ( includeRemote || ! isRemote )
122 && (vMAttrib & vMAttribMask) == vMAttribMask ) {
123
124 /* add local volumes at the front, remote
125 volumes at the end */
126 if (isRemote)
127 vols[nlocal + nremote++] = volPB.volumeParam.ioVRefNum;
128 else {
129 if (nremote > 0)
130 BlockMoveData(vols+nlocal, vols+nlocal+1,
131 nremote*sizeof(short));
132 vols[nlocal++] = volPB.volumeParam.ioVRefNum;
133 }
134
135 /* list full? */
136 if ((nlocal + nremote) >= *count) break;
137 }
138 }
139bail:
140 *count = (nlocal + nremote);
141 return err;
142}
143
144
145 /* FindApplication iterates through mounted volumes
146 searching for an application with the given creator
147 type. If includeRemote is true, then remote volumes
148 will be searched (after local ones) for an application
149 with the creator type. */
150
151#define kMaxVols 20
152
153/* Hacked to output to appName */
154
7baa887c 155OSErr FindApplication(OSType appCreator, Boolean includeRemote, Str255 appName, FSSpec* appSpec) {
c9e227f4
RN
156 short rRefNums[kMaxVols];
157 long i, volCount;
158 DTPBRec desktopPB;
159 OSErr err;
c9e227f4
RN
160
161 /* get a list of volumes - with desktop files */
162 volCount = kMaxVols;
163 err = BuildVolumeList(includeRemote, rRefNums, &volCount,
164 (1<<bHasDesktopMgr) );
165 if (err != noErr) return err;
166
167 /* iterate through the list */
168 for (i=0; i<volCount; i++) {
169
170 /* has a desktop file? */
171 desktopPB.ioCompletion = NULL;
172 desktopPB.ioVRefNum = rRefNums[i];
173 desktopPB.ioNamePtr = NULL;
174 desktopPB.ioIndex = 0;
175 err = PBDTGetPath(&desktopPB);
176 if (err != noErr) continue;
177
178 /* has the correct app?? */
179 desktopPB.ioFileCreator = appCreator;
180 desktopPB.ioNamePtr = appName;
181 err = PBDTGetAPPLSync(&desktopPB);
182 if (err != noErr) continue;
183
184 /* make a file spec referring to it */
185 err = FSMakeFSSpec(rRefNums[i],
186 desktopPB.ioAPPLParID, appName,
187 appSpec);
188 if (err != noErr) continue;
189
190 /* found it! */
191 return noErr;
192
193 }
194 return fnfErr;
195}
196
197/* END CODE SAMPLE FROM TECHNOTE 1002 (http://developer.apple.com/technotes/tn/tn1002.html) */
198
7baa887c
RN
199//yeah, duplicated code
200pascal OSErr FSpGetFullPath(const FSSpec *spec,
201 short *fullPathLength,
202 Handle *fullPath)
203{
204 OSErr result;
205 OSErr realResult;
206 FSSpec tempSpec;
207 CInfoPBRec pb;
208
209 *fullPathLength = 0;
210 *fullPath = NULL;
211
212
213 /* Default to noErr */
214 realResult = result = noErr;
215
216 /* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */
217/*
218 if ( spec->name[0] == 0 )
219 {
220 result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec);
221 }
222 else
223 {
224*/
225 /* Make a copy of the input FSSpec that can be modified */
226 BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
227/* }*/
228
229 if ( result == noErr )
230 {
231 if ( tempSpec.parID == fsRtParID )
232 {
233 /* The object is a volume */
234
235 /* Add a colon to make it a full pathname */
236 ++tempSpec.name[0];
237 tempSpec.name[tempSpec.name[0]] = ':';
238
239 /* We're done */
240 result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
241 }
242 else
243 {
244 /* The object isn't a volume */
245
246 /* Is the object a file or a directory? */
247 pb.dirInfo.ioNamePtr = tempSpec.name;
248 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
249 pb.dirInfo.ioDrDirID = tempSpec.parID;
250 pb.dirInfo.ioFDirIndex = 0;
251 result = PBGetCatInfoSync(&pb);
252 /* Allow file/directory name at end of path to not exist. */
253 realResult = result;
254 if ( (result == noErr) || (result == fnfErr) )
255 {
256 /* if the object is a directory, append a colon so full pathname ends with colon */
257 if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
258 {
259 ++tempSpec.name[0];
260 tempSpec.name[tempSpec.name[0]] = ':';
261 }
262
263 /* Put the object name in first */
264 result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
265 if ( result == noErr )
266 {
267 /* Get the ancestor directory names */
268 pb.dirInfo.ioNamePtr = tempSpec.name;
269 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
270 pb.dirInfo.ioDrParID = tempSpec.parID;
271 do /* loop until we have an error or find the root directory */
272 {
273 pb.dirInfo.ioFDirIndex = -1;
274 pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
275 result = PBGetCatInfoSync(&pb);
276 if ( result == noErr )
277 {
278 /* Append colon to directory name */
279 ++tempSpec.name[0];
280 tempSpec.name[tempSpec.name[0]] = ':';
281
282 /* Add directory name to beginning of fullPath */
283 (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]);
284 result = MemError();
285 }
286 } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
287 }
288 }
289 }
290 }
291
292 if ( result == noErr )
293 {
294 /* Return the length */
295 *fullPathLength = GetHandleSize(*fullPath);
296 result = realResult; /* return realResult in case it was fnfErr */
297 }
298 else
299 {
300 /* Dispose of the handle and return NULL and zero length */
301 if ( *fullPath != NULL )
302 {
303 DisposeHandle(*fullPath);
304 }
305 *fullPath = NULL;
306 *fullPathLength = 0;
307 }
308
309 return ( result );
310}
311
312//
313// On the mac there are two ways to open a file - one is through apple events and the
314// finder, another is through mime types.
315//
316// So, really there are two ways to implement wxFileType...
317//
318// Mime types are only available on OS 8.1+ through the InternetConfig API
319//
320// Much like the old-style file manager, it has 3 levels of flexibility for its methods -
321// Low - which means you have to iterate yourself through the mime database
322// Medium - which lets you sort of cache the database if you want to use lowlevel functions
323// High - which requires access to the database every time
324//
325// We want to be efficient (i.e. professional :) ) about it, so we use a combo of low
326// and mid-level functions
327//
328// TODO: Should we call ICBegin/ICEnd? Then where?
329//
330
331// debug helper
332inline void wxLogMimeDebug(const wxChar* szMsg, OSStatus status)
333{
334 wxLogDebug(wxString::Format(wxT("%s LINE:%i OSERROR:%i"), szMsg, __LINE__, (int)status));
335}
336
337// in case we're compiling in non-GUI mode
338class WXDLLEXPORT wxIcon;
339
340bool wxFileTypeImpl::SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt)
341{
03271fa7
RN
342 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
343
7baa887c
RN
344 return FALSE;
345}
346
347bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int index)
348{
03271fa7
RN
349 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
350
7baa887c
RN
351 return FALSE;
352}
353
354bool wxFileTypeImpl::GetOpenCommand(wxString *openCmd,
355 const wxFileType::MessageParameters& params) const
356{
357 wxString cmd = GetCommand(wxT("open"));
358
359 *openCmd = wxFileType::ExpandCommand(cmd, params);
360
361 return !openCmd->empty();
362}
363
364bool
365wxFileTypeImpl::GetPrintCommand(wxString *printCmd,
366 const wxFileType::MessageParameters& params)
367 const
368{
369 wxString cmd = GetCommand(wxT("print"));
370
371 *printCmd = wxFileType::ExpandCommand(cmd, params);
372
373 return !printCmd->empty();
374}
375
376//
377// Internet Config vs. Launch Services
378//
379// From OS 8 on there was internet config...
380// However, OSX and its finder does not use info
381// from Internet Config at all - the Internet Config
382// database ONLY CONTAINS APPS THAT ARE CLASSIC APPS
383// OR REGISTERED THROUGH INTERNET CONFIG
384//
385// Therefore on OSX in order for the open command to be useful
386// we need to go straight to launch services
387//
388
389#if defined(__DARWIN__)
390
391//on darwin, use launch services
392#include "LaunchServices.h"
393
c9e227f4 394wxString wxFileTypeImpl::GetCommand(const wxString& verb) const
7dc3cc31 395{
03271fa7 396 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
7baa887c
RN
397
398 if(verb == wxT("open"))
399 {
400 ICMapEntry entry;
401 ICGetMapEntry( (ICInstance) m_manager->m_hIC,
402 (Handle) m_manager->m_hDatabase,
403 m_lIndex, &entry);
404
405 wxString sCurrentExtension = wxMacMakeStringFromPascal(entry.extension);
406 sCurrentExtension = sCurrentExtension.Right(sCurrentExtension.Length()-1 );
407
408 //type, creator, ext, roles, outapp (FSRef), outappurl
409 CFURLRef cfurlAppPath;
410 OSStatus status = LSGetApplicationForInfo (kLSUnknownType,
411 kLSUnknownCreator,
412 wxMacCFStringHolder(sCurrentExtension, wxLocale::GetSystemEncoding()),
413 kLSRolesAll,
414 NULL,
415 &cfurlAppPath);
416
417 if(status == noErr)
418 {
419 CFStringRef cfsUnixPath = CFURLCopyFileSystemPath(cfurlAppPath, kCFURLPOSIXPathStyle);
420 CFRelease(cfurlAppPath);
421
422 //PHEW! Success!
423 if(cfsUnixPath)
424 return wxMacCFStringHolder(cfsUnixPath).AsString(wxLocale::GetSystemEncoding());
425 }
426 else
427 {
428 wxLogDebug(wxString::Format(wxT("%i - %s - %i"),
429 __LINE__,
430 wxT("LSGetApplicationForInfo failed."),
431 (int)status));
432 }
433 }
434
435 return wxEmptyString;
436}
437
438#else //carbon/classic implementation
439
440wxString wxFileTypeImpl::GetCommand(const wxString& verb) const
441{
03271fa7 442 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
c9e227f4
RN
443
444 if(verb == wxT("open"))
7dc3cc31 445 {
c9e227f4 446 ICMapEntry entry;
c02af653
RN
447 ICGetMapEntry( (ICInstance) m_manager->m_hIC,
448 (Handle) m_manager->m_hDatabase,
449 m_lIndex, &entry);
c9e227f4 450
c9e227f4
RN
451 //The entry in the mimetype database only contains the app
452 //that's registered - it may not exist... we need to remap the creator
453 //type and find the right application
7baa887c
RN
454
455 // THIS IS REALLY COMPLICATED :\. There are a lot of conversions going
456 // on here.
c9e227f4 457 Str255 outName;
7baa887c
RN
458 FSSpec outSpec;
459 if(FindApplication(entry.fileCreator, false, outName, &outSpec) != noErr)
c9e227f4
RN
460 return wxEmptyString;
461
7baa887c
RN
462 Handle outPathHandle;
463 short outPathSize;
464 OSErr err = FSpGetFullPath(&outSpec, &outPathSize, &outPathHandle);
465
466 if(err == noErr)
467 {
468 char* szPath = *outPathHandle;
469 wxString sClassicPath(szPath, wxConvLocal, outPathSize);
470#if defined(__DARWIN__)
471 //Classic Path --> Unix (OSX) Path
472 CFURLRef finalURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
473 wxMacCFStringHolder(sClassicPath, wxLocale::GetSystemEncoding()),
474 kCFURLHFSPathStyle,
475 false); //false == not a directory
476
477 //clean up memory from the classic path handle
478 DisposeHandle(outPathHandle);
479
480 if(finalURL)
481 {
482 CFStringRef cfsUnixPath = CFURLCopyFileSystemPath(finalURL, kCFURLPOSIXPathStyle);
483 CFRelease(finalURL);
484
485 //PHEW! Success!
486 if(cfsUnixPath)
487 return wxMacCFStringHolder(cfsUnixPath).AsString(wxLocale::GetSystemEncoding());
488 }
489#else //classic HFS path acceptable
490 return sClassicPath;
491#endif
492 }
493 else
494 {
495 wxLogMimeDebug(wxT("FSpGetFullPath failed."), (OSStatus)err);
496 }
7dc3cc31 497 }
c9e227f4
RN
498 return wxEmptyString;
499}
7baa887c 500#endif //!DARWIN
c9e227f4 501
0be2eb2f
RN
502bool wxFileTypeImpl::GetDescription(wxString *desc) const
503{
504 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
505
506 ICMapEntry entry;
507 ICGetMapEntry( (ICInstance) m_manager->m_hIC,
508 (Handle) m_manager->m_hDatabase,
509 m_lIndex, &entry);
510
511 *desc = wxMacMakeStringFromPascal(entry.entryName);
512 return true;
513}
514
c9e227f4
RN
515bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
516{
03271fa7 517 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
c9e227f4
RN
518
519 ICMapEntry entry;
c02af653
RN
520 ICGetMapEntry( (ICInstance) m_manager->m_hIC,
521 (Handle) m_manager->m_hDatabase,
522 m_lIndex, &entry);
c9e227f4
RN
523
524 //entry has period in it
525 wxString sCurrentExtension = wxMacMakeStringFromPascal(entry.extension);
526 extensions.Add( sCurrentExtension.Right(sCurrentExtension.Length()-1) );
527 return true;
528}
529
530bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
531{
03271fa7 532 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
c9e227f4
RN
533
534 ICMapEntry entry;
c02af653
RN
535 ICGetMapEntry( (ICInstance) m_manager->m_hIC,
536 (Handle) m_manager->m_hDatabase,
537 m_lIndex, &entry);
c9e227f4
RN
538
539 *mimeType = wxMacMakeStringFromPascal(entry.MIMEType);
540 return true;
7dc3cc31
VS
541}
542
4d2976ad
VS
543bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const
544{
545 wxString s;
546
547 if (GetMimeType(&s))
548 {
549 mimeTypes.Clear();
550 mimeTypes.Add(s);
551 return TRUE;
552 }
553 else
554 return FALSE;
555}
556
da0766ab 557bool wxFileTypeImpl::GetIcon(wxIconLocation *WXUNUSED(icon)) const
7dc3cc31 558{
03271fa7
RN
559 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
560
7dc3cc31
VS
561 // no such file type or no value or incorrect icon entry
562 return FALSE;
563}
564
c9e227f4 565size_t wxFileTypeImpl::GetAllCommands(wxArrayString * verbs, wxArrayString * commands,
e40298d5 566 const wxFileType::MessageParameters& params) const
007ae8d0 567{
03271fa7
RN
568 wxASSERT_MSG( m_manager != NULL , wxT("Bad wxFileType") );
569
570 wxString sCommand;
571 size_t ulCount = 0;
572
573 if(GetOpenCommand(&sCommand, params))
574 {
575 verbs->Add(wxString(wxT("open")));
576 commands->Add(sCommand);
577 ++ulCount;
578 }
579
580 return ulCount;
f040060e
GD
581}
582
c9e227f4 583void wxMimeTypesManagerImpl::Initialize(int mailcapStyles, const wxString& extraDir)
f040060e 584{
c9e227f4 585 wxASSERT_MSG(m_hIC == NULL, wxT("Already initialized wxMimeTypesManager!"));
007ae8d0 586
5af840f1
RN
587 //some apps (non-wx) use the 'plst' resource instead
588/*
589 CFBundleRef cfbMain = CFBundleGetMainBundle();
590 wxCFDictionary cfdInfo( CFBundleGetInfoDictionary(cfbMain), wxCF_RETAIN );
591 wxString sLog;
592 cfdInfo.PrintOut(sLog);
593 wxLogDebug(sLog);
594*/
595
c9e227f4
RN
596 //start internet config - log if there's an error
597 //the second param is the signature of the application, also known
598 //as resource ID 0. However, as per some recent discussions, we may not
599 //have a signature for this app, so a generic 'APPL' which is the executable
600 //type will work for now
601 OSStatus status = ICStart( (ICInstance*) &m_hIC, 'APPL');
602
603 if(status != noErr)
7dc3cc31 604 {
7baa887c 605 wxLogDebug(wxT("Could not initialize wxMimeTypesManager!"));
c9e227f4 606 wxASSERT( false );
03271fa7 607 m_hIC = NULL;
c9e227f4 608 return;
7dc3cc31 609 }
c9e227f4
RN
610
611 ICAttr attr;
612 m_hDatabase = (void**) NewHandle(0);
613 status = ICFindPrefHandle( (ICInstance) m_hIC, kICMapping, &attr, (Handle) m_hDatabase );
614
615 //the database file can be corrupt (on OSX its
616 //~/Library/Preferences/com.apple.internetconfig.plist)
617 //- bail if it is
618 if(status != noErr)
7dc3cc31 619 {
c9e227f4 620 ClearData();
7baa887c 621 wxLogDebug(wxT("Corrupt Mime Database!"));
c9e227f4 622 return;
7dc3cc31 623 }
c9e227f4
RN
624
625 //obtain the number of entries in the map
626 status = ICCountMapEntries( (ICInstance) m_hIC, (Handle) m_hDatabase, &m_lCount );
627 wxASSERT( status == noErr );
7baa887c
RN
628 /*
629 //debug stuff
630 ICMapEntry entry;
631 long pos;
632
633 for(long i = 1; i <= m_lCount; ++i)
634 {
635 OSStatus status = ICGetIndMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase, i, &pos, &entry);
636
637 if(status == noErr)
638 {
639 wxString sCreator = wxMacMakeStringFromPascal(entry.creatorAppName);
640 wxString sCurrentExtension = wxMacMakeStringFromPascal(entry.extension);
641 wxString sMIMEType = wxMacMakeStringFromPascal(entry.MIMEType);
642
643 wxFileTypeImpl impl;
644 impl.Init(this, pos);
645
646 if(sMIMEType == wxT("text/html") && sCurrentExtension == wxT(".html"))
647 {
648 wxString cmd;
649 impl.GetOpenCommand (&cmd,
650 wxFileType::MessageParameters (wxT("http://www.google.com"),
651 _T("")));
652
653 wxPrintf(wxT("APP: [%s]\n"), cmd.c_str());
654 }
655 }
656 }
657 */
c9e227f4
RN
658}
659
660void wxMimeTypesManagerImpl::ClearData()
661{
662 if(m_hIC != NULL)
7dc3cc31 663 {
c9e227f4
RN
664 DisposeHandle((Handle)m_hDatabase);
665 //this can return an error, but we don't really care that much about it
666 ICStop( (ICInstance) m_hIC );
667 m_hIC = NULL;
7dc3cc31 668 }
c9e227f4
RN
669}
670
03271fa7
RN
671//
672// Q) Iterating through the map - why does it use if (err == noErr) instead of just asserting?
673// A) Some intermediate indexes are bad while subsequent ones may be good. Its wierd, I know.
674//
675
c9e227f4
RN
676// extension -> file type
677wxFileType* wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& e)
678{
679 wxASSERT_MSG( m_hIC != NULL, wxT("wxMimeTypesManager not Initialized!") );
680
c9e227f4
RN
681 //low level functions - iterate through the database
682 ICMapEntry entry;
c9e227f4
RN
683 long pos;
684
685 for(long i = 1; i <= m_lCount; ++i)
7dc3cc31 686 {
c9e227f4
RN
687 OSStatus status = ICGetIndMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase, i, &pos, &entry);
688
689 if(status == noErr)
690 {
691 wxString sCurrentExtension = wxMacMakeStringFromPascal(entry.extension);
692 if( sCurrentExtension.Right(sCurrentExtension.Length()-1) == e ) //entry has period in it
693 {
03271fa7 694 wxFileType* pFileType = new wxFileType();
c9e227f4 695 pFileType->m_impl->Init((wxMimeTypesManagerImpl*)this, pos);
03271fa7 696 return pFileType;
c9e227f4
RN
697 }
698 }
7dc3cc31 699 }
c9e227f4 700
03271fa7 701 return NULL;
7dc3cc31
VS
702}
703
704// MIME type -> extension -> file type
c9e227f4 705wxFileType* wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
7dc3cc31 706{
c9e227f4
RN
707 wxASSERT_MSG( m_hIC != NULL, wxT("wxMimeTypesManager not Initialized!") );
708
709 //low level functions - iterate through the database
710 ICMapEntry entry;
c9e227f4
RN
711 long pos;
712
713 for(long i = 1; i <= m_lCount; ++i)
714 {
715 OSStatus status = ICGetIndMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase, i, &pos, &entry);
716 wxASSERT_MSG( status == noErr, wxString::Format(wxT("Error: %d"), (int)status) );
717
718 if(status == noErr)
719 {
720 if( wxMacMakeStringFromPascal(entry.MIMEType) == mimeType)
721 {
03271fa7 722 wxFileType* pFileType = new wxFileType();
c9e227f4 723 pFileType->m_impl->Init((wxMimeTypesManagerImpl*)this, pos);
03271fa7 724 return pFileType;
c9e227f4
RN
725 }
726 }
727 }
728
03271fa7 729 return NULL;
7dc3cc31
VS
730}
731
732size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
733{
c9e227f4 734 wxASSERT_MSG( m_hIC != NULL, wxT("wxMimeTypesManager not Initialized!") );
7dc3cc31 735
c9e227f4
RN
736 //low level functions - iterate through the database
737 ICMapEntry entry;
c9e227f4 738 long pos;
03271fa7 739
7baa887c 740 long lStartCount = (long) mimetypes.GetCount();
c9e227f4
RN
741
742 for(long i = 1; i <= m_lCount; ++i)
743 {
744 OSStatus status = ICGetIndMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase, i, &pos, &entry);
745 if( status == noErr )
746 mimetypes.Add( wxMacMakeStringFromPascal(entry.MIMEType) );
747 }
748
7baa887c 749 return mimetypes.GetCount() - lStartCount;
7dc3cc31
VS
750}
751
7baa887c
RN
752
753pascal OSStatus MoreProcGetProcessTypeSignature(
754 const ProcessSerialNumberPtr pPSN,
755 OSType *pProcessType,
756 OSType *pCreator)
757{
758 OSStatus anErr = noErr;
759 ProcessInfoRec infoRec;
760 ProcessSerialNumber localPSN;
761
762 infoRec.processInfoLength = sizeof(ProcessInfoRec);
763 infoRec.processName = nil;
764 infoRec.processAppSpec = nil;
765
766 if ( pPSN == nil ) {
767 localPSN.highLongOfPSN = 0;
768 localPSN.lowLongOfPSN = kCurrentProcess;
769 } else {
770 localPSN = *pPSN;
771 }
772
773 anErr = GetProcessInformation(&localPSN, &infoRec);
774 if (anErr == noErr)
775 {
776 *pProcessType = infoRec.processType;
777 *pCreator = infoRec.processSignature;
778 }
779
780 return anErr;
781}//end MoreProcGetProcessTypeSignature
782
5af840f1
RN
783//
784//
785// TODO: clean this up, its messy
786//
787//
788//
789
790#include "wx/mac/corefoundation/cfstring.h"
791#include "wx/intl.h" //wxLocale for wxCFString
792
793#define wxCF_RELEASE true
794#define wxCF_RETAIN false
795
796// ----------------------------------------------------------------------------
797// wxCFDictionary
798// ----------------------------------------------------------------------------
799
800class wxCFDictionary
dd9b4b7f 801{
5af840f1
RN
802public:
803 wxCFDictionary(CFTypeRef ref, bool bRetain = wxCF_RELEASE)
804 {
805 m_cfmdRef = (CFMutableDictionaryRef) ref;
806 if(bRetain == wxCF_RETAIN && ref)
807 CFRetain(ref);
808 }
809
810 wxCFDictionary(CFIndex cfiSize = 0)
811 {
812 CFDictionaryKeyCallBacks kcbs;
813 CFDictionaryValueCallBacks vcbs;
814 BuildKeyCallbacks(&kcbs);
815 BuildValueCallbacks(&vcbs);
816
817 m_cfmdRef = CFDictionaryCreateMutable(
818 kCFAllocatorDefault, cfiSize, &kcbs, &vcbs);
819
820 }
821
822 ~wxCFDictionary()
823 { Clear(); }
824
825 void Clear()
826 {if(m_cfmdRef) CFRelease(m_cfmdRef);}
827
828 static const void* RetainProc(CFAllocatorRef, const void* v)
829 { return (const void*) CFRetain(v); }
830
831 static void ReleaseProc(CFAllocatorRef, const void* v)
832 { CFRelease(v); }
833
834 void MakeMutable(CFIndex cfiSize = 0)
835 {
836 CFDictionaryRef oldref = (CFDictionaryRef) m_cfmdRef;
837
838 m_cfmdRef = CFDictionaryCreateMutableCopy(
839 kCFAllocatorDefault,
840 cfiSize,
841 oldref);
842
843 CFRelease(oldref);
844 }
845
846 void BuildKeyCallbacks(CFDictionaryKeyCallBacks* pCbs)
847 {
848 pCbs->version = 0;
849 pCbs->retain = RetainProc;
850 pCbs->release = ReleaseProc;
851 pCbs->copyDescription = NULL;
852 pCbs->equal = NULL;
853 pCbs->hash = NULL;
854 }
855
856 void BuildValueCallbacks(CFDictionaryValueCallBacks* pCbs)
857 {
858 pCbs->version = 0;
859 pCbs->retain = RetainProc;
860 pCbs->release = ReleaseProc;
861 pCbs->copyDescription = NULL;
862 pCbs->equal = NULL;
863 }
864
865 operator CFTypeRef () const
866 { return (CFTypeRef)m_cfmdRef; }
867
868 CFDictionaryRef GetCFDictionary() const
869 { return (CFDictionaryRef)m_cfmdRef; }
870
871 CFMutableDictionaryRef GetCFMutableDictionary()
872 { return (CFMutableDictionaryRef) m_cfmdRef; }
873
874 CFTypeRef operator [] (CFTypeRef cftEntry) const
875 {
876 wxASSERT(IsValid());
877 return (CFTypeRef) CFDictionaryGetValue((CFDictionaryRef)m_cfmdRef, cftEntry);
878 }
879
880 CFIndex GetCount() const
881 {
882 wxASSERT(IsValid());
883 return CFDictionaryGetCount((CFDictionaryRef)m_cfmdRef);
884 }
885
886 void Add(CFTypeRef cftKey, CFTypeRef cftValue)
887 {
888 wxASSERT(IsValid());
889 wxASSERT(Exists(cftKey) == false);
890 CFDictionaryAddValue(m_cfmdRef, cftKey, cftValue);
891 }
892
893 void Remove(CFTypeRef cftKey)
894 {
895 wxASSERT(IsValid());
896 wxASSERT(Exists(cftKey));
897 CFDictionaryRemoveValue(m_cfmdRef, cftKey);
898 }
899
900 void Set(CFTypeRef cftKey, CFTypeRef cftValue)
901 {
902 wxASSERT(IsValid());
903 wxASSERT(Exists(cftKey));
904 CFDictionarySetValue(m_cfmdRef, cftKey, cftValue);
905 }
906
907 bool Exists(CFTypeRef cftKey) const
908 {
909 wxASSERT(IsValid());
910 return CFDictionaryContainsKey((CFDictionaryRef)m_cfmdRef, cftKey) == true;
911 }
912
913 bool IsOk() const {return m_cfmdRef != NULL; }
914
915 bool IsValid() const
916 {
917 return IsOk() && CFGetTypeID((CFTypeRef)m_cfmdRef) == CFDictionaryGetTypeID();
918 }
919
920 void PrintOut(wxString& sMessage)
921 {
922 PrintOutDictionary(sMessage, m_cfmdRef);
923 }
924
925 static void PrintOutDictionary(wxString& sMessage, CFDictionaryRef cfdRef)
926 {
927 CFIndex cfiCount = CFDictionaryGetCount(cfdRef);
928 CFTypeRef* pKeys = new CFTypeRef[cfiCount];
929 CFTypeRef* pValues = new CFTypeRef[cfiCount];
930
931 CFDictionaryGetKeysAndValues(cfdRef, pKeys, pValues);
932
933 for(CFIndex i = 0; i < cfiCount; ++i)
934 {
935 wxString sKey = wxMacCFStringHolder(CFCopyTypeIDDescription(CFGetTypeID(pKeys[i]))).AsString();
936 wxString sValue = wxMacCFStringHolder(CFCopyTypeIDDescription(CFGetTypeID(pValues[i]))).AsString();
937
938 sMessage <<
939 wxString::Format(wxT("[{#%d} Key : %s]"), (int) i,
940 sKey.c_str());
941
942 PrintOutType(sMessage, sKey, pKeys[i]);
943
944 sMessage <<
945 wxString::Format(wxT("\n\t[Value : %s]"),
946 sValue.c_str());
947
948 PrintOutType(sMessage, sValue, pValues[i]);
949
950 sMessage << wxT("\n");
951 }
952
953 delete[] pKeys;
954 delete[] pValues;
955 }
956
957 static void PrintOutArray(wxString& sMessage, CFArrayRef cfaRef)
958 {
959
960 for(CFIndex i = 0; i < CFArrayGetCount(cfaRef); ++i)
961 {
962 wxString sValue = wxMacCFStringHolder(CFCopyTypeIDDescription(CFGetTypeID(
963 CFArrayGetValueAtIndex(cfaRef, i)
964 ))).AsString();
965
966 sMessage <<
967 wxString::Format(wxT("\t\t[{#%d} ArrayValue : %s]\n"), (int) i,
968 sValue.c_str());
969
970 PrintOutType(sMessage, sValue, CFArrayGetValueAtIndex(cfaRef, i));
971 }
972 }
973
974 static void PrintOutType(wxString& sMessage, wxString sValue, CFTypeRef cfRef)
975 {
976 sMessage << wxT(" {");
977
978 if(sValue == wxT("CFString"))
979 {
980 sMessage << wxMacCFStringHolder((CFStringRef)cfRef, false).AsString();
981 }
982 else if(sValue == wxT("CFNumber"))
983 {
984 int nOut;
985 CFNumberGetValue((CFNumberRef)cfRef, kCFNumberIntType, &nOut);
986 sMessage << nOut;
987 }
988 else if(sValue == wxT("CFDictionary"))
989 {
990 PrintOutDictionary(sMessage, (CFDictionaryRef)cfRef);
991 }
992 else if(sValue == wxT("CFArray"))
993 {
994 PrintOutArray(sMessage, (CFArrayRef)cfRef);
995 }
996 else if(sValue == wxT("CFBoolean"))
997 {
998 sMessage << (cfRef == kCFBooleanTrue ? wxT("true") : wxT("false"));
999 }
1000 else if(sValue == wxT("CFURL"))
1001 {
1002 sMessage << wxMacCFStringHolder(CFURLCopyPath((CFURLRef) cfRef)).AsString();
1003 }
1004 else
1005 {
1006 sMessage << wxT("*****UNKNOWN TYPE******");
1007 }
1008
1009 sMessage << wxT("} ");
1010 }
1011
1012#if wxUSE_MIMETYPE
1013 void MakeValidXML();
1014#endif
1015
1016 CFTypeRef WriteAsXML()
1017 {
1018 return CFPropertyListCreateXMLData(kCFAllocatorDefault, m_cfmdRef);
1019 }
1020
1021 bool ReadAsXML(CFTypeRef cfData, wxString* pErrorMsg = NULL)
1022 {
1023 Clear();
1024 CFStringRef cfsError=NULL;
1025 m_cfmdRef = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData(
1026 kCFAllocatorDefault,
1027 (CFDataRef)cfData,
1028 kCFPropertyListMutableContainersAndLeaves,
1029 &cfsError );
1030 if(cfsError)
1031 {
1032 if(pErrorMsg)
1033 *pErrorMsg = wxMacCFStringHolder(cfsError).AsString();
1034 else
1035 CFRelease(cfsError);
1036 }
1037
1038 return m_cfmdRef != NULL;
1039 }
1040 private:
1041 CFMutableDictionaryRef m_cfmdRef;
1042};
1043
1044// ----------------------------------------------------------------------------
1045// wxCFArray
1046// ----------------------------------------------------------------------------
1047
1048class wxCFArray
1049{
1050public:
1051 wxCFArray(CFTypeRef ref, bool bRetain = wxCF_RELEASE)
1052 {
1053 m_cfmaRef = (CFMutableArrayRef)ref;
1054 if(bRetain == wxCF_RETAIN && ref)
1055 CFRetain(ref);
1056 }
1057
1058 wxCFArray(CFIndex cfiSize = 0) : m_cfmaRef(NULL)
1059 { Create(cfiSize); }
1060
1061 ~wxCFArray()
1062 { Clear(); }
1063
1064 void MakeMutable(CFIndex cfiSize = 0)
1065 {
1066 wxASSERT(IsValid());
1067
1068 CFMutableArrayRef oldref = m_cfmaRef;
1069 m_cfmaRef = CFArrayCreateMutableCopy(
1070 kCFAllocatorDefault,
1071 cfiSize,
1072 (CFArrayRef)oldref);
1073 CFRelease(oldref);
1074 }
1075
1076 void BuildCallbacks(CFArrayCallBacks* pCbs)
1077 {
1078 pCbs->version = 0;
1079 pCbs->retain = RetainProc;
1080 pCbs->release = ReleaseProc;
1081 pCbs->copyDescription = NULL;
1082 pCbs->equal = NULL;
1083 }
1084
1085 void Create(CFIndex cfiSize = 0)
1086 {
1087 Clear();
1088 CFArrayCallBacks cb;
1089 BuildCallbacks(&cb);
1090
1091 m_cfmaRef = CFArrayCreateMutable(kCFAllocatorDefault, cfiSize, &cb);
1092 }
1093
1094 void Clear()
1095 {if(m_cfmaRef) CFRelease(m_cfmaRef);}
1096
1097 static const void* RetainProc(CFAllocatorRef, const void* v)
1098 { return (const void*) CFRetain(v); }
1099
1100 static void ReleaseProc(CFAllocatorRef, const void* v)
1101 { CFRelease(v); }
1102
1103 operator CFTypeRef () const
1104 { return (CFTypeRef)m_cfmaRef; }
1105
1106 CFArrayRef GetCFArray() const
1107 { return (CFArrayRef)m_cfmaRef; }
1108
1109 CFMutableArrayRef GetCFMutableArray()
1110 { return (CFMutableArrayRef) m_cfmaRef; }
1111
1112 CFTypeRef operator [] (CFIndex cfiIndex) const
1113 {
1114 wxASSERT(IsValid());
1115 return (CFTypeRef) CFArrayGetValueAtIndex((CFArrayRef)m_cfmaRef, cfiIndex);
1116 }
1117
1118 CFIndex GetCount()
1119 {
1120 wxASSERT(IsValid());
1121 return CFArrayGetCount((CFArrayRef)m_cfmaRef);
1122 }
1123
1124 void Add(CFTypeRef cftValue)
1125 {
1126 wxASSERT(IsValid());
1127 CFArrayAppendValue(m_cfmaRef, cftValue);
1128 }
1129
1130 void Remove(CFIndex cfiIndex)
1131 {
1132 wxASSERT(IsValid());
1133 wxASSERT(cfiIndex < GetCount());
1134 CFArrayRemoveValueAtIndex(m_cfmaRef, cfiIndex);
1135 }
1136
1137 void Set(CFIndex cfiIndex, CFTypeRef cftValue)
1138 {
1139 wxASSERT(IsValid());
1140 wxASSERT(cfiIndex < GetCount());
1141 CFArraySetValueAtIndex(m_cfmaRef, cfiIndex, cftValue);
1142 }
1143
1144 bool IsOk() const {return m_cfmaRef != NULL; }
1145
1146 bool IsValid() const
1147 {
1148 return IsOk() && CFGetTypeID((CFTypeRef)m_cfmaRef) == CFArrayGetTypeID();
1149 }
1150
1151#if wxUSE_MIMETYPE
1152 void MakeValidXML();
1153#endif
1154
1155private:
1156 CFMutableArrayRef m_cfmaRef;
1157};
1158
1159// ----------------------------------------------------------------------------
1160// wxCFString
1161// ----------------------------------------------------------------------------
1162
1163class wxCFString
1164{
1165public:
1166 wxCFString(CFTypeRef ref, bool bRetain = wxCF_RELEASE) : m_Holder((CFStringRef)ref, bRetain == wxCF_RELEASE)
1167 { }
1168
1169 wxCFString(const wxChar* szString) : m_Holder(wxString(szString), wxLocale::GetSystemEncoding())
1170 { }
1171
1172 wxCFString(const wxString& sString) : m_Holder(sString, wxLocale::GetSystemEncoding())
1173 { }
1174
1175 operator CFTypeRef() const
b40a9d37 1176 {return (CFTypeRef) ((CFStringRef) m_Holder); }
5af840f1
RN
1177
1178 bool IsOk() { return ((CFTypeRef)(*this)) != NULL; }
1179
1180 wxString BuildWXString() {return m_Holder.AsString(); }
1181
1182private:
1183 wxMacCFStringHolder m_Holder;
1184};
1185
1186// ----------------------------------------------------------------------------
1187// wxCFNumber
1188// ----------------------------------------------------------------------------
1189
1190class wxCFNumber
1191{
1192public:
1193 wxCFNumber(int nValue)
1194 {
1195 m_cfnRef = CFNumberCreate(kCFAllocatorDefault,
1196 kCFNumberIntType, &nValue);
1197 }
1198
1199 wxCFNumber(CFTypeRef ref, bool bRetain = wxCF_RELEASE) : m_cfnRef((CFNumberRef)ref)
1200 {
1201 if(bRetain == wxCF_RETAIN && ref)
1202 CFRetain(ref);
1203 }
1204
1205 ~wxCFNumber()
1206 { if(m_cfnRef) CFRelease(m_cfnRef); }
1207
1208
1209 operator CFTypeRef() const
1210 { return (CFTypeRef) m_cfnRef; }
1211
1212 int GetValue()
1213 {
1214 int nOut;
1215 CFNumberGetValue(
1216 m_cfnRef,
1217 kCFNumberIntType,
1218 &nOut
1219 );
1220
1221 return nOut;
1222 }
1223
1224 bool IsOk() { return m_cfnRef != NULL; }
1225
1226private:
1227 CFNumberRef m_cfnRef;
1228};
1229
1230// ----------------------------------------------------------------------------
1231// wxCFURL
1232// ----------------------------------------------------------------------------
1233
1234class wxCFURL
1235{
1236public:
1237 wxCFURL(CFTypeRef ref = NULL, bool bRetain = wxCF_RELEASE) : m_cfurlRef((CFURLRef)ref)
1238 {
1239 if(bRetain == wxCF_RETAIN && ref)
1240 CFRetain(ref);
1241 }
1242 wxCFURL(const wxCFString& URLString, CFTypeRef BaseURL = NULL)
1243 {
1244 Create(URLString, BaseURL);
1245 }
1246
1247 void Create(const wxCFString& URLString, CFTypeRef BaseURL = NULL)
1248 {
1249 m_cfurlRef = CFURLCreateWithString(
1250 kCFAllocatorDefault,
1251 (CFStringRef)(CFTypeRef)URLString,
1252 (CFURLRef) BaseURL);
1253 }
1254
1255 ~wxCFURL() {if(m_cfurlRef) CFRelease(m_cfurlRef);}
1256
1257 wxString BuildWXString()
1258 {
1259 return wxCFString(CFURLCopyPath(m_cfurlRef)).BuildWXString();
1260 }
1261
1262 operator CFTypeRef() const
1263 { return (CFTypeRef)m_cfurlRef; }
1264
1265 bool IsOk() { return m_cfurlRef != NULL; }
1266private:
1267 CFURLRef m_cfurlRef;
1268};
1269
1270// ----------------------------------------------------------------------------
1271// wxCFData
1272// ----------------------------------------------------------------------------
1273
1274#define wxCFDATA_RELEASEBUFFER 1
1275#define wxCFDATA_RETAINBUFFER 0
1276
1277class wxCFData
1278{
1279public:
1280 wxCFData(CFTypeRef ref, bool bRetain = wxCF_RELEASE) : m_cfdaRef((CFDataRef)ref)
1281 {
1282 if(bRetain == wxCF_RETAIN && ref)
1283 CFRetain(ref);
1284 }
1285 wxCFData(const UInt8* pBytes, CFIndex len, bool bKeep = wxCFDATA_RELEASEBUFFER)
1286 {
1287 if(bKeep == wxCFDATA_RELEASEBUFFER)
1288 {
1289 m_cfdaRef = CFDataCreateWithBytesNoCopy
1290 (kCFAllocatorDefault, pBytes, len, kCFAllocatorDefault);
1291 }
1292 else
1293 {
1294 m_cfdaRef = CFDataCreate(kCFAllocatorDefault, pBytes, len);
1295 }
1296 }
1297 ~wxCFData() {if(m_cfdaRef) CFRelease(m_cfdaRef);}
1298
1299 const UInt8* GetValue()
1300 {
1301 return CFDataGetBytePtr(m_cfdaRef);
1302 }
1303
1304 CFIndex GetCount()
1305 {
1306 return CFDataGetLength(m_cfdaRef);
1307 }
1308
1309 operator CFTypeRef() const
1310 { return (CFTypeRef)m_cfdaRef; }
1311
1312 bool IsOk() { return m_cfdaRef != NULL; }
1313private:
1314 CFDataRef m_cfdaRef;
1315};
1316
1317void wxCFDictionary::MakeValidXML()
1318{
1319 CFIndex cfiCount = GetCount();
1320 CFTypeRef* pKeys = new CFTypeRef[cfiCount];
1321 CFTypeRef* pValues = new CFTypeRef[cfiCount];
1322
1323 CFDictionaryGetKeysAndValues(m_cfmdRef, pKeys, pValues);
1324
1325 //for plist xml format all dictionary keys must be cfstrings and no values in
1326 //the dictionary or subkeys/values can be NULL
1327 //Also, CFURLs are not allowed
1328 for(CFIndex i = 0; i < cfiCount; ++i)
1329 {
1330 //must be an array, dictionary, string, bool, or int and cannot be null
1331 //and dictionaries can only contain cfstring keys
1332 CFTypeRef cfRef = pValues[i];
1333 if(!pKeys[i] ||
1334 CFGetTypeID(pKeys[i]) != CFStringGetTypeID() ||
1335 !cfRef)
1336 {
1337 Remove(pKeys[i]);
1338 --i;
1339 --cfiCount;
1340 delete[] pKeys;
1341 delete[] pValues;
1342 pKeys = new CFTypeRef[cfiCount];
1343 pValues = new CFTypeRef[cfiCount];
1344 CFDictionaryGetKeysAndValues(m_cfmdRef, pKeys, pValues);
1345 }
1346 else if (CFGetTypeID(cfRef) == CFArrayGetTypeID())
1347 {
1348 CFRetain(cfRef);
1349 wxCFArray cfaCurrent(cfRef);
1350 cfaCurrent.MakeMutable();
1351 cfaCurrent.MakeValidXML();
1352 Set(pKeys[i], cfaCurrent);
1353 }
1354 else if (CFGetTypeID(cfRef) == CFDictionaryGetTypeID())
1355 {
1356 CFRetain(cfRef);
1357 wxCFDictionary cfdCurrent(cfRef);
1358 cfdCurrent.MakeMutable();
1359 cfdCurrent.MakeValidXML();
1360 Set(pKeys[i], cfdCurrent);
1361 }
1362 else if( ( CFGetTypeID(cfRef) == CFStringGetTypeID() ||
1363 CFGetTypeID(cfRef) == CFNumberGetTypeID() ||
1364 CFGetTypeID(cfRef) == CFBooleanGetTypeID() ) == false )
1365 {
1366 Remove(pKeys[i]);
1367 --i;
1368 --cfiCount;
1369 delete[] pKeys;
1370 delete[] pValues;
1371 pKeys = new CFTypeRef[cfiCount];
1372 pValues = new CFTypeRef[cfiCount];
1373 CFDictionaryGetKeysAndValues(m_cfmdRef, pKeys, pValues);
1374 }
1375 }
1376
1377 delete[] pValues;
1378 delete[] pKeys;
1379}
1380
1381void wxCFArray::MakeValidXML()
1382{
1383 for(CFIndex i = 0; i < GetCount(); ++i)
1384 {
1385 //must be an array, dictionary, string, bool, or int and cannot be null
1386 //and dictionaries can only contain cfstring keys
1387 CFTypeRef cfRef = (*this)[i];
1388 if(!cfRef)
1389 {
1390 Remove(i);
1391 --i;
1392 }
1393 else if (CFGetTypeID(cfRef) == CFArrayGetTypeID())
1394 {
1395 CFRetain(cfRef);
1396 wxCFArray cfaCurrent(cfRef);
1397 cfaCurrent.MakeMutable();
1398 cfaCurrent.MakeValidXML();
1399 Set(i, cfaCurrent);
1400 }
1401 else if (CFGetTypeID(cfRef) == CFDictionaryGetTypeID())
1402 {
1403 CFRetain(cfRef);
1404 wxCFDictionary cfdCurrent(cfRef);
1405 cfdCurrent.MakeMutable();
1406 cfdCurrent.MakeValidXML();
1407 Set(i, cfdCurrent);
1408 }
1409 else if( ( CFGetTypeID(cfRef) == CFStringGetTypeID() ||
1410 CFGetTypeID(cfRef) == CFNumberGetTypeID() ||
1411 CFGetTypeID(cfRef) == CFBooleanGetTypeID() ) == false )
1412 {
1413 Remove(i);
1414 --i;
1415 }
1416 }
1417}
1418
1419//
1420//
1421//
1422// END TODO
1423//
1424//
1425//
1426
1427wxFileType* wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
1428{
1429 bool bInfoSuccess = false;
1430
1431 const wxArrayString& asExtensions = ftInfo.GetExtensions();
1432 size_t dwFoundIndex = 0;
1433 if(!asExtensions.GetCount())
1434 {
1435 wxLogDebug(wxT("Must have extension to associate with"));
1436 }
1437
1438 //Find and write to Info.plist in main bundle (note that some other
1439 //apps have theirs named differently, i.e. IE's is named Info-macos.plist
1440 //some apps (non-wx) use the 'plst' resource instead
1441 CFBundleRef cfbMain = CFBundleGetMainBundle();
1442 if(cfbMain)
1443 {
1444 UInt32 dwBundleType, dwBundleCreator;
1445 CFBundleGetPackageInfo(cfbMain, &dwBundleType, &dwBundleCreator);
1446
1447 //if launching terminal non-app version will be 'BNDL' (generic bundle, maybe in other cases too),
1448 //which will give us the incorrect info.plist path
1449 //otherwise it will be 'APPL', or in the case of a framework,
1450 //'FMWK'
1451 if(dwBundleType == 'APPL')
1452 {
1453
1454 wxCFURL cfurlBundleLoc((CFTypeRef)CFBundleCopyBundleURL(cfbMain));
1455// wxCFURL cfurlBundleLoc((CFTypeRef)CFBundleCopyExecutableURL(cfbMain));
1456 wxString sInfoPath;
1457// sInfoPath << wxT("file://");
1458 sInfoPath << cfurlBundleLoc.BuildWXString();
1459 sInfoPath << wxT("Contents/Info.plist");
1460
1461// wxCFDictionary cfdInfo( CFBundleGetInfoDictionary(cfbMain), wxCF_RETAIN );
1462 wxCFDictionary cfdInfo;
1463 bool bInfoOpenSuccess = false;
1464 wxFile indictfile;
1465 if(indictfile.Open(sInfoPath, wxFile::read));
1466 {
1467 CFIndex cfiBufLen = (CFIndex) indictfile.Length();
1468 const UInt8* pBuffer = new UInt8[cfiBufLen];
1469 indictfile.Read((void*)pBuffer, cfiBufLen);
1470 wxCFData cfdaInDict(pBuffer, cfiBufLen);
1471 wxString sError;
1472 bInfoOpenSuccess = cfdInfo.ReadAsXML(cfdaInDict, &sError);
1473 if(!bInfoOpenSuccess)
1474 wxLogDebug(sError);
1475 indictfile.Close();
1476 }
1477 if(bInfoOpenSuccess)
1478 {
1479 cfdInfo.MakeMutable( cfdInfo.GetCount() + 1 );
1480
1481 wxCFArray cfaDocTypes( cfdInfo[ wxCFString(wxT("CFBundleDocumentTypes")) ], wxCF_RETAIN );
1482
1483 bool bAddDocTypesArrayToDictionary = cfaDocTypes.IsOk() == false;
1484 if(bAddDocTypesArrayToDictionary)
1485 cfaDocTypes.Create();
1486 else
1487 cfaDocTypes.MakeMutable( cfaDocTypes.GetCount() + 1 );
1488
1489 bool bEntryFound = false;
1490
1491 //search for duplicate
1492 CFIndex i;
1493 for(i = 0; i < cfaDocTypes.GetCount(); ++i)
1494 {
1495 wxCFDictionary cfdDocTypeEntry( cfaDocTypes[i], wxCF_RETAIN );
1496
1497 //A lot of apps dont do to mime types for some reason
1498 //so we go by extensions only
1499 wxCFArray cfaExtensions( cfdDocTypeEntry[ wxCFString(wxT("CFBundleTypeExtensions")) ],
1500 wxCF_RETAIN );
1501
1502 if(cfaExtensions.IsOk() == false)
1503 continue;
1504
1505 for(CFIndex iExt = 0; iExt < cfaExtensions.GetCount(); ++iExt)
1506 {
1507 for (size_t iWXExt = 0; iWXExt < asExtensions.GetCount(); ++iWXExt)
1508 {
1509 if(asExtensions[iWXExt] ==
1510 wxCFString(cfaExtensions[iExt], wxCF_RETAIN).BuildWXString())
1511 {
1512 bEntryFound = true;
1513 dwFoundIndex = iWXExt;
1514 break;
1515 }
1516 } //end of wxstring array
1517
1518 if(bEntryFound)
1519 break;
1520 } //end for cf array
1521
1522 if(bEntryFound)
1523 break;
1524 }//end for doctypes
1525
1526 wxCFDictionary cfdNewEntry;
1527
1528 if(!ftInfo.GetDescription().empty())
1529 {
1530 cfdNewEntry.Add( wxCFString(wxT("CFBundleTypeName")),
1531 wxCFString(ftInfo.GetDescription()) );
1532 }
1533
1534 if(!ftInfo.GetIconFile().empty())
1535 {
1536 cfdNewEntry.Add( wxCFString(wxT("CFBundleTypeIconFile")),
1537 wxCFString(ftInfo.GetIconFile()) );
1538 }
1539
1540
1541 wxCFArray cfaOSTypes;
1542 wxCFArray cfaExtensions;
1543 wxCFArray cfaMimeTypes;
1544
1545
1546 //OSTypes is a cfarray of four-char-codes - '****' for unrestricted
1547 cfaOSTypes.Add( wxCFString(wxT("****")) );
1548 cfdNewEntry.Add( wxCFString(wxT("CFBundleTypeOSTypes")), cfaOSTypes );
1549
1550 if(ftInfo.GetExtensionsCount() != 0) //'*' for unrestricted
1551 {
1552 for(size_t iExtension = 0; iExtension < (size_t)ftInfo.GetExtensionsCount(); ++iExtension)
1553 {
1554 cfaExtensions.Add( wxCFString( asExtensions[iExtension] ) );
1555 }
1556
1557 cfdNewEntry.Add( wxCFString(wxT("CFBundleTypeExtensions")), cfaExtensions );
1558 }
1559
1560 if(!ftInfo.GetMimeType().empty())
1561 {
1562 cfaMimeTypes.Add( wxCFString(ftInfo.GetMimeType()) );
1563 cfdNewEntry.Add( wxCFString(wxT("CFBundleTypeMIMETypes")), cfaMimeTypes );
1564 }
1565
1566 // Editor - can perform all actions
1567 // Viewer - all actions except manipulation/saving
1568 // None - can perform no actions
1569 cfdNewEntry.Add( wxCFString(wxT("CFBundleTypeRole")), wxCFString(wxT("Editor")) );
1570
1571 // Is application bundled?
1572 cfdNewEntry.Add( wxCFString(wxT("LSTypeIsPackage")), kCFBooleanTrue );
1573
1574 if(bEntryFound)
1575 cfaDocTypes.Set(i, cfdNewEntry);
1576 else
1577 cfaDocTypes.Add(cfdNewEntry);
1578
1579 //
1580 // set the doc types array in the muted dictionary
1581 //
1582
1583 if(bAddDocTypesArrayToDictionary)
1584 cfdInfo.Add(wxCFString(wxT("CFBundleDocumentTypes")), cfaDocTypes);
1585 else
1586 cfdInfo.Set(wxCFString(wxT("CFBundleDocumentTypes")), cfaDocTypes);
1587
1588 cfdInfo.MakeValidXML();
1589
1590 wxFile outdictfile;
1591 if(outdictfile.Open(sInfoPath, wxFile::write))
1592 {
1593 wxCFData cfdaInfo(cfdInfo.WriteAsXML());
1594 if(cfdaInfo.IsOk())
1595 {
1596 if(outdictfile.Write(cfdaInfo.GetValue(), cfdaInfo.GetCount()) !=
1597 (wxFileOffset)cfdaInfo.GetCount())
1598 {
1599 wxLogDebug(wxT("error in writing to file"));
1600 }
1601 else
1602 {
1603 bInfoSuccess = true;
1604//#if defined(__DARWIN__)
1605// //force launch services to update its database for the finder
1606// OSStatus status = LSRegisterURL((CFURLRef)(CFTypeRef)cfurlBundleLoc, true);
1607// if(status != noErr)
1608// {
1609// wxLogDebug(wxT("LSRegisterURL Failed."));
1610// }
1611//#endif
1612 }
1613 outdictfile.Close();
1614 }
1615 else
1616 {
1617 outdictfile.Close();
1618 wxLogDebug(wxT("Could not read in new dictionary"));
1619 }
1620 }
1621 else
1622 {
1623 wxLogDebug(wxString(wxT("Could not open [")) +
1624 sInfoPath + wxT("] for writing."));
1625 }
1626 }
1627 else
1628 {
1629 wxLogDebug(wxT("No info dictionary in main bundle"));
1630 }
1631 }
1632 else
1633 {
1634 wxLogDebug(wxT("Can only call associate from bundled app within XXX.app"));
1635 }
1636 }
1637 else
1638 {
1639 wxLogDebug(wxT("No main bundle"));
1640 }
1641
1642#if defined(__DARWIN__)
1643 if(!bInfoSuccess)
1644 return NULL;
1645#endif
c9e227f4
RN
1646 //on mac you have to embed it into the mac's file reference resource ('FREF' I believe)
1647 //or, alternately, you could just add an entry to m_hDatabase, but you'd need to get
1648 //the app's signature somehow...
007ae8d0 1649
7baa887c
RN
1650 OSType processType,
1651 creator;
1652 OSStatus status = MoreProcGetProcessTypeSignature(NULL,&processType, &creator);
1653
1654 if(status == noErr)
1655 {
1656 Str255 psCreatorName;
1657 FSSpec dummySpec;
1658 status = FindApplication(creator, false, psCreatorName, &dummySpec);
1659
1660 if(status == noErr)
1661 {
1662
1663 //get the file type if it exists -
1664 //if it really does then modify the database then save it,
1665 //otherwise we need to create a whole new entry
5af840f1 1666 wxFileType* pFileType = GetFileTypeFromExtension(asExtensions[dwFoundIndex]);
7baa887c
RN
1667 if(pFileType)
1668 {
1669 ICMapEntry entry;
1670 ICGetMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase,
1671 pFileType->m_impl->m_lIndex, &entry);
1672
fcc7c995 1673 memcpy(entry.creatorAppName, psCreatorName, sizeof(Str255));
7baa887c
RN
1674 entry.fileCreator = creator;
1675
1676 status = ICSetMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase,
1677 pFileType->m_impl->m_lIndex, &entry);
1678
1679 //success
1680 if(status == noErr)
5af840f1
RN
1681 {
1682 //kICAttrNoChange means we don't care about attributes such as
1683 //locking in the database
1684// status = ICSetPrefHandle((ICInstance) m_hIC, kICMapping,
1685// kICAttrNoChange, (Handle) m_hDatabase);
1686// if(status == noErr)
1687 return pFileType;
1688// else
1689// {
1690// wxLogDebug(wxString::Format(wxT("%i - %s"), (int)status, wxT("ICSetPrefHandle failed.")));
1691 // }
1692 }
7baa887c
RN
1693 else
1694 {
1695 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICSetMapEntry failed.")));
1696 }
1697
1698 //failure - cleanup
1699 delete pFileType;
1700 }
1701 else
1702 {
1703 //TODO: Maybe force all 3 of these to be non-empty?
1704 Str255 psExtension;
1705 Str255 psMimeType;
1706 Str255 psDescription;
1707
5af840f1 1708 wxMacStringToPascal(wxString(wxT(".")) + ftInfo.GetExtensions()[0], psExtension);
7baa887c
RN
1709 wxMacStringToPascal(ftInfo.GetMimeType(), psMimeType);
1710 wxMacStringToPascal(ftInfo.GetDescription(), psDescription);
1711
1712 Str255 psPostCreatorName;
1713 wxMacStringToPascal(wxT(""), psPostCreatorName);
1714
1715
1716 //add the entry to the database
7baa887c
RN
1717 ICMapEntry entry;
1718 entry.totalLength = sizeof(ICMapEntry);
1719 entry.fixedLength = kICMapFixedLength;
1720 entry.version = 0;
1721 entry.fileType = 0; //TODO: File type?
1722 entry.fileCreator = creator;
1723 entry.postCreator = 0;
1724 entry.flags = kICMapDataForkBit; //TODO: Maybe resource is valid by default too?
b94fa9f5 1725 PLstrcpy( entry.extension , psExtension ) ;
fcc7c995
RN
1726 memcpy(entry.creatorAppName, psCreatorName, sizeof(Str255));
1727 memcpy(entry.postAppName, psPostCreatorName, sizeof(Str255));
1728 memcpy(entry.MIMEType, psMimeType, sizeof(Str255));
1729 memcpy(entry.entryName, psDescription, sizeof(Str255));
7baa887c
RN
1730
1731 status = ICAddMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase, &entry);
1732
1733 if(status == noErr)
1734 {
1735 //kICAttrNoChange means we don't care about attributes such as
1736 //locking in the database
5af840f1
RN
1737 // status = ICSetPrefHandle((ICInstance) m_hIC, kICMapping,
1738 // kICAttrNoChange, (Handle) m_hDatabase);
7baa887c
RN
1739
1740 //return the entry in the database if successful
5af840f1
RN
1741 // if(status == noErr)
1742 return GetFileTypeFromExtension(ftInfo.GetMimeType());
1743 // else
1744 // {
1745 // wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICSetPrefHandle failed.")));
1746 // }
7baa887c
RN
1747 }
1748 else
1749 {
1750 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICAppMapEntry failed.")));
1751 }
1752 }
1753 } //end if FindApplcation was successful
1754 else
1755 {
1756 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("FindApplication failed.")));
1757 }
1758 } //end if it could obtain app's signature
1759 else
1760 {
1761 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("GetProcessSignature failed.")));
1762 }
007ae8d0
GD
1763 return NULL;
1764}
f040060e
GD
1765
1766bool
7baa887c 1767wxMimeTypesManagerImpl::Unassociate(wxFileType *pFileType)
f040060e 1768{
5af840f1
RN
1769 wxASSERT(pFileType);
1770 bool bInfoSuccess = false;
1771
1772 wxArrayString asExtensions;
1773 pFileType->GetExtensions(asExtensions);
1774
1775 if(!asExtensions.GetCount())
1776 {
1777 wxLogDebug(wxT("Must have extension to disassociate"));
1778 return FALSE;
1779 }
1780
1781 //Find and write to Info.plist in main bundle (note that some other
1782 //apps have theirs named differently, i.e. IE's is named Info-macos.plist
1783 //some apps (non-wx) use the 'plst' resource instead
1784 CFBundleRef cfbMain = CFBundleGetMainBundle();
1785 if(cfbMain)
1786 {
1787 UInt32 dwBundleType, dwBundleCreator;
1788 CFBundleGetPackageInfo(cfbMain, &dwBundleType, &dwBundleCreator);
1789
1790 //if launching terminal non-app version will be 'BNDL' (generic bundle, maybe in other cases too),
1791 //which will give us the incorrect info.plist path
1792 //otherwise it will be 'APPL', or in the case of a framework,
1793 //'FMWK'
1794 if(dwBundleType == 'APPL')
1795 {
1796
1797 wxCFURL cfurlBundleLoc((CFTypeRef)CFBundleCopyBundleURL(cfbMain));
1798// wxCFURL cfurlBundleLoc((CFTypeRef)CFBundleCopyExecutableURL(cfbMain));
1799 wxString sInfoPath;
1800// sInfoPath << wxT("file://");
1801 sInfoPath << cfurlBundleLoc.BuildWXString();
1802 sInfoPath << wxT("Contents/Info.plist");
1803
1804// wxCFDictionary cfdInfo( (CFTypeRef) CFBundleGetInfoDictionary(cfbMain), wxCF_RETAIN );
1805 wxCFDictionary cfdInfo;
1806 bool bInfoOpenSuccess = false;
1807 wxFile indictfile;
1808 if(indictfile.Open(sInfoPath, wxFile::read));
1809 {
1810 CFIndex cfiBufLen = (CFIndex) indictfile.Length();
1811 const UInt8* pBuffer = new UInt8[cfiBufLen];
1812 indictfile.Read((void*)pBuffer, cfiBufLen);
1813 wxCFData cfdaInDict(pBuffer, cfiBufLen);
1814 wxString sError;
1815 bInfoOpenSuccess = cfdInfo.ReadAsXML(cfdaInDict, &sError);
1816 if(!bInfoOpenSuccess)
1817 wxLogDebug(sError);
1818 indictfile.Close();
1819 }
1820 if(bInfoOpenSuccess)
1821 {
1822 cfdInfo.MakeMutable( cfdInfo.GetCount() + 1 );
1823
1824 wxCFArray cfaDocTypes( cfdInfo[ wxCFString(wxT("CFBundleDocumentTypes")) ], wxCF_RETAIN );
1825
1826 if(cfaDocTypes.IsOk())
1827 {
1828 bool bEntryFound = false;
1829
1830 //search for duplicate
1831 CFIndex i;
1832 for(i = 0; i < cfaDocTypes.GetCount(); ++i)
1833 {
1834 wxCFDictionary cfdDocTypeEntry( cfaDocTypes[i], wxCF_RETAIN );
1835
1836 //A lot of apps dont do to mime types for some reason
1837 //so we go by extensions only
1838 wxCFArray cfaExtensions( cfdDocTypeEntry[ wxCFString(wxT("CFBundleTypeExtensions")) ],
1839 wxCF_RETAIN );
1840
1841 if(cfaExtensions.IsOk() == false)
1842 continue;
1843
1844 for(CFIndex iExt = 0; iExt < cfaExtensions.GetCount(); ++iExt)
1845 {
1846 for (size_t iWXExt = 0; iWXExt < asExtensions.GetCount(); ++iWXExt)
1847 {
1848 if(asExtensions[iWXExt] ==
1849 wxCFString(cfaExtensions[iExt], wxCF_RETAIN).BuildWXString())
1850 {
1851 bEntryFound = true;
1852 cfaDocTypes.Remove(i);
1853 cfdInfo.Set( wxCFString(wxT("CFBundleDocumentTypes")) , cfaDocTypes );
1854 break;
1855 }
1856 } //end of wxstring array
1857
1858 if(bEntryFound)
1859 break;
1860 } //end for cf array
1861
1862 if(bEntryFound)
1863 break;
1864 }//end for doctypes
1865
1866 if(bEntryFound)
1867 {
1868 cfdInfo.MakeValidXML();
1869
1870 wxFile outdictfile;
1871 if(outdictfile.Open(sInfoPath, wxFile::write))
1872 {
1873 wxCFData cfdaInfo(cfdInfo.WriteAsXML());
1874 if(cfdaInfo.IsOk())
1875 {
1876 if(outdictfile.Write(cfdaInfo.GetValue(), cfdaInfo.GetCount()) !=
1877 (wxFileOffset)cfdaInfo.GetCount())
1878 {
1879 wxLogDebug(wxT("error in writing to file"));
1880 }
1881 else
1882 {
1883 bInfoSuccess = true;
1884//#if defined(__DARWIN__)
1885// //force launch services to update its database for the finder
1886// OSStatus status = LSRegisterURL((CFURLRef)(CFTypeRef)cfurlBundleLoc, true);
1887// if(status != noErr)
1888// {
1889// wxLogDebug(wxT("LSRegisterURL Failed."));
1890// }
1891//#endif
1892 }
1893 outdictfile.Close();
1894 }
1895 else
1896 {
1897 outdictfile.Close();
1898 wxLogDebug(wxT("Could not read in new dictionary"));
1899 }
1900 }
1901 else
1902 {
1903 wxLogDebug(wxString(wxT("Could not open [")) +
1904 sInfoPath + wxT("] for writing."));
1905 }
1906 }
1907 else
1908 {
1909 wxLogDebug(wxT("Entry not found to remove"));
1910 wxString sPrintOut;
1911 wxCFDictionary::PrintOutArray(sPrintOut, (CFArrayRef)(CFTypeRef)cfaDocTypes);
1912 wxLogDebug(sPrintOut);
1913 for(size_t i = 0; i < asExtensions.GetCount(); ++i)
1914 wxLogDebug(asExtensions[i]);
1915 }
1916 }
1917 else
1918 {
1919 wxLogDebug(wxT("No doc types array found"));
1920 wxString sPrintOut; cfdInfo.PrintOut(sPrintOut); wxLogDebug(sPrintOut);
1921 }
1922 }
1923 else
1924 {
1925 wxLogDebug(wxT("No info dictionary in main bundle"));
1926 }
1927 }
1928 else
1929 {
1930 wxLogDebug(wxT("Can only call associate from bundled app within XXX.app"));
1931 }
1932 }
1933 else
1934 {
1935 wxLogDebug(wxT("No main bundle"));
1936 }
1937
1938#if defined(__DARWIN__)
1939 if(!bInfoSuccess)
fcc7c995 1940 return FALSE;
5af840f1
RN
1941#endif
1942
c9e227f4
RN
1943 //this should be as easy as removing the entry from the database and then saving
1944 //the database
7baa887c
RN
1945 OSStatus status = ICDeleteMapEntry( (ICInstance) m_hIC, (Handle) m_hDatabase,
1946 pFileType->m_impl->m_lIndex);
1947
1948 if(status == noErr)
1949 {
1950 //kICAttrNoChange means we don't care about attributes such as
1951 //locking in the database
5af840f1
RN
1952// status = ICSetPrefHandle((ICInstance) m_hIC, kICMapping,
1953// kICAttrNoChange, (Handle) m_hDatabase);
7baa887c 1954
5af840f1 1955// if(status == noErr)
7baa887c 1956 return TRUE;
5af840f1
RN
1957// else
1958// {
1959// wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICSetPrefHandle failed.")));
1960// }
7baa887c
RN
1961
1962 }
1963 else
1964 {
1965 wxLogDebug(wxString::Format(wxT("%i - %s"), __LINE__, wxT("ICDeleteMapEntry failed.")));
1966 }
1967
f040060e
GD
1968 return FALSE;
1969}
5af840f1
RN
1970/*
1971 CFWriteStreamRef cfwsInfo = CFWriteStreamCreateWithFile(
1972 kCFAllocatorDefault,
1973 (CFURLRef) (CFTypeRef)cfurlInfoLoc );
1974
1975// CFShow(cfdInfo);
1976 if(cfwsInfo)
1977 {
1978 Boolean bOpened = CFWriteStreamOpen(cfwsInfo);
1979 if(bOpened)
1980 {
1981 CFStringRef cfsError;
1982 CFIndex cfiWritten = CFPropertyListWriteToStream((CFPropertyListRef)(CFTypeRef)cfdInfo,
1983 cfwsInfo,
1984 kCFPropertyListXMLFormat_v1_0, //100
1985 &cfsError);
1986 if(cfsError && cfiWritten == 0)
1987 {
1988 wxLogDebug(wxCFString(cfsError).BuildWXString());
1989 wxString sMessage;
1990 cfdInfo.PrintOut(sMessage);
1991 wxLogDebug(sMessage);
1992 }
1993 else
1994 {
1995 bInfoSuccess = true;
1996//#if defined(__DARWIN__)
1997// //force launch services to update its database for the finder
1998// OSStatus status = LSRegisterURL((CFURLRef)(CFTypeRef)cfurlBundleLoc, true);
1999// if(status != noErr)
2000// {
2001// wxLogDebug(wxT("LSRegisterURL Failed."));
2002// }
2003//#endif
2004 }
2005
2006 CFWriteStreamClose(cfwsInfo);
f040060e 2007
5af840f1 2008*/
4b8f9d46 2009#endif //wxUSE_MIMETYPE