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