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