diff options
Diffstat (limited to 'macosx/tclMacOSXBundle.c')
-rw-r--r-- | macosx/tclMacOSXBundle.c | 351 |
1 files changed, 222 insertions, 129 deletions
diff --git a/macosx/tclMacOSXBundle.c b/macosx/tclMacOSXBundle.c index 28e4977..dad3733 100644 --- a/macosx/tclMacOSXBundle.c +++ b/macosx/tclMacOSXBundle.c @@ -1,63 +1,147 @@ /* * tclMacOSXBundle.c -- * - * This file implements functions that inspect CFBundle structures - * on MacOS X. - * - * Copyright 2001, Apple Computer, Inc. - * - * The following terms apply to all files originating from Apple - * Computer, Inc. ("Apple") and associated with the software - * unless explicitly disclaimed in individual files. - * - * - * Apple hereby grants permission to use, copy, modify, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized - * uses. Modifications to this software may be copyrighted by - * their authors and need not follow the licensing terms - * described here, provided that the new terms are clearly - * indicated on the first page of each file where they apply. - * - * - * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE - * SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, - * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF - * THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, - * EVEN IF APPLE OR THE AUTHORS HAVE BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. APPLE, THE AUTHORS AND - * DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS - * SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND APPLE,THE - * AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE - * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * GOVERNMENT USE: If you are acquiring this software on behalf - * of the U.S. government, the Government shall have only - * "Restricted Rights" in the software and related documentation - * as defined in the Federal Acquisition Regulations (FARs) in - * Clause 52.227.19 (c) (2). If you are acquiring the software - * on behalf of the Department of Defense, the software shall be - * classified as "Commercial Computer Software" and the - * Government shall have only "Restricted Rights" as defined in - * Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the - * foregoing, the authors grant the U.S. Government and others - * acting in its behalf permission to use and distribute the - * software in accordance with the terms specified in this - * license. + * This file implements functions that inspect CFBundle structures on + * MacOS X. + * + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2003-2009 Daniel A. Steffen <das@users.sourceforge.net> + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclPort.h" #ifdef HAVE_COREFOUNDATION #include <CoreFoundation/CoreFoundation.h> + +#ifndef TCL_DYLD_USE_DLFCN +/* + * Use preferred dlfcn API on 10.4 and later + */ +# if !defined(NO_DLFCN_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 +# define TCL_DYLD_USE_DLFCN 1 +# else +# define TCL_DYLD_USE_DLFCN 0 +# endif +#endif /* TCL_DYLD_USE_DLFCN */ + +#ifndef TCL_DYLD_USE_NSMODULE +/* + * Use deprecated NSModule API only to support 10.3 and earlier: + */ +# if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 +# define TCL_DYLD_USE_NSMODULE 1 +# else +# define TCL_DYLD_USE_NSMODULE 0 +# endif +#endif /* TCL_DYLD_USE_NSMODULE */ + +#if TCL_DYLD_USE_DLFCN +#include <dlfcn.h> +#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 +/* + * Support for weakly importing dlfcn API. + */ +extern void * dlsym(void *handle, const char *symbol) + WEAK_IMPORT_ATTRIBUTE; +extern char * dlerror(void) WEAK_IMPORT_ATTRIBUTE; +#endif +#endif /* TCL_DYLD_USE_DLFCN */ + +#if TCL_DYLD_USE_NSMODULE #include <mach-o/dyld.h> +#endif + +#if (TCL_DYLD_USE_DLFCN && MAC_OS_X_VERSION_MIN_REQUIRED < 1040) || \ + (MAC_OS_X_VERSION_MIN_REQUIRED < 1050) +MODULE_SCOPE long tclMacOSXDarwinRelease; +#endif + +#ifdef TCL_DEBUG_LOAD +#define TclLoadDbgMsg(m, ...) \ + do { \ + fprintf(stderr, "%s:%d: %s(): " m ".\n", \ + strrchr(__FILE__, '/')+1, __LINE__, __func__, \ + ##__VA_ARGS__); \ + } while (0) +#else +#define TclLoadDbgMsg(m, ...) +#endif /* TCL_DEBUG_LOAD */ + +/* + * Forward declaration of functions defined in this file: + */ + +static short OpenResourceMap(CFBundleRef bundleRef); + #endif /* HAVE_COREFOUNDATION */ + +/* + *---------------------------------------------------------------------- + * + * OpenResourceMap -- + * + * Wrapper that dynamically acquires the address for the function + * CFBundleOpenBundleResourceMap before calling it, since it is only + * present in full CoreFoundation on Mac OS X and not in CFLite on pure + * Darwin. Factored out because it is moderately ugly code. + * + *---------------------------------------------------------------------- + */ + +#ifdef HAVE_COREFOUNDATION +static short +OpenResourceMap( + CFBundleRef bundleRef) +{ + static int initialized = FALSE; + static short (*openresourcemap)(CFBundleRef) = NULL; + + if (!initialized) { +#if TCL_DYLD_USE_DLFCN +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 + if (tclMacOSXDarwinRelease >= 8) +#endif + { + openresourcemap = dlsym(RTLD_NEXT, + "CFBundleOpenBundleResourceMap"); +#ifdef TCL_DEBUG_LOAD + if (!openresourcemap) { + const char *errMsg = dlerror(); + + TclLoadDbgMsg("dlsym() failed: %s", errMsg); + } +#endif /* TCL_DEBUG_LOAD */ + } + if (!openresourcemap) +#endif /* TCL_DYLD_USE_DLFCN */ + { +#if TCL_DYLD_USE_NSMODULE + if (NSIsSymbolNameDefinedWithHint( + "_CFBundleOpenBundleResourceMap", "CoreFoundation")) { + NSSymbol nsSymbol = NSLookupAndBindSymbolWithHint( + "_CFBundleOpenBundleResourceMap", "CoreFoundation"); + + if (nsSymbol) { + openresourcemap = NSAddressOfSymbol(nsSymbol); + } + } +#endif /* TCL_DYLD_USE_NSMODULE */ + } + initialized = TRUE; + } + + if (openresourcemap) { + return openresourcemap(bundleRef); + } + return -1; +} + +#endif /* HAVE_COREFOUNDATION */ + /* *---------------------------------------------------------------------- * @@ -65,13 +149,12 @@ * * Given the bundle name for a shared library, this routine sets * libraryPath to the Resources/Scripts directory in the framework - * package. If hasResourceFile is true, it will also open the main + * package. If hasResourceFile is true, it will also open the main * resource file for the bundle. * - * * Results: * TCL_OK if the bundle could be opened, and the Scripts folder found. - * TCL_ERROR otherwise. + * TCL_ERROR otherwise. * * Side effects: * libraryVariableName may be set, and the resource file opened. @@ -82,13 +165,13 @@ int Tcl_MacOSXOpenBundleResources( Tcl_Interp *interp, - CONST char *bundleName, - int hasResourceFile, - int maxPathLen, - char *libraryPath) + const char *bundleName, + int hasResourceFile, + int maxPathLen, + char *libraryPath) { - return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, - NULL, hasResourceFile, maxPathLen, libraryPath); + return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, NULL, + hasResourceFile, maxPathLen, libraryPath); } /* @@ -96,16 +179,15 @@ Tcl_MacOSXOpenBundleResources( * * Tcl_MacOSXOpenVersionedBundleResources -- * - * Given the bundle and version name for a shared library (version - * name can be NULL to indicate latest version), this routine sets - * libraryPath to the Resources/Scripts directory in the framework - * package. If hasResourceFile is true, it will also open the main - * resource file for the bundle. - * + * Given the bundle and version name for a shared library (version name + * can be NULL to indicate latest version), this routine sets libraryPath + * to the Resources/Scripts directory in the framework package. If + * hasResourceFile is true, it will also open the main resource file for + * the bundle. * * Results: * TCL_OK if the bundle could be opened, and the Scripts folder found. - * TCL_ERROR otherwise. + * TCL_ERROR otherwise. * * Side effects: * libraryVariableName may be set, and the resource file opened. @@ -116,104 +198,115 @@ Tcl_MacOSXOpenBundleResources( int Tcl_MacOSXOpenVersionedBundleResources( Tcl_Interp *interp, - CONST char *bundleName, - CONST char *bundleVersion, - int hasResourceFile, - int maxPathLen, - char *libraryPath) + const char *bundleName, + const char *bundleVersion, + int hasResourceFile, + int maxPathLen, + char *libraryPath) { #ifdef HAVE_COREFOUNDATION - CFBundleRef bundleRef; + CFBundleRef bundleRef, versionedBundleRef = NULL; CFStringRef bundleNameRef; CFURLRef libURL; libraryPath[0] = '\0'; - bundleNameRef = CFStringCreateWithCString(NULL, - bundleName, kCFStringEncodingUTF8); + bundleNameRef = CFStringCreateWithCString(NULL, bundleName, + kCFStringEncodingUTF8); bundleRef = CFBundleGetBundleWithIdentifier(bundleNameRef); CFRelease(bundleNameRef); if (bundleVersion && bundleRef) { - /* create bundle from bundleVersion subdirectory of 'Versions' */ - CFBundleRef versionedBundleRef = NULL; - CFURLRef versionedBundleURL = NULL; - CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL, - bundleVersion, kCFStringEncodingUTF8); + /* + * Create bundle from bundleVersion subdirectory of 'Versions'. + */ + CFURLRef bundleURL = CFBundleCopyBundleURL(bundleRef); + if (bundleURL) { - CFStringRef bundleTailRef = CFURLCopyLastPathComponent(bundleURL); - if (bundleTailRef) { - if (CFStringCompare(bundleTailRef,bundleVersionRef,0) - == kCFCompareEqualTo) { - versionedBundleRef = bundleRef; + CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL, + bundleVersion, kCFStringEncodingUTF8); + + if (bundleVersionRef) { + CFComparisonResult versionComparison = kCFCompareLessThan; + CFStringRef bundleTailRef = CFURLCopyLastPathComponent( + bundleURL); + + if (bundleTailRef) { + versionComparison = CFStringCompare(bundleTailRef, + bundleVersionRef, 0); + CFRelease(bundleTailRef); } - CFRelease(bundleTailRef); - } - } - if (bundleURL && !versionedBundleRef) { - CFURLRef versURL = CFURLCreateCopyAppendingPathComponent(NULL, - bundleURL, CFSTR("Versions"), TRUE); - if (versURL) { - versionedBundleURL = CFURLCreateCopyAppendingPathComponent( - NULL, versURL, bundleVersionRef, TRUE); - CFRelease(versURL); + if (versionComparison != kCFCompareEqualTo) { + CFURLRef versURL = CFURLCreateCopyAppendingPathComponent( + NULL, bundleURL, CFSTR("Versions"), TRUE); + + if (versURL) { + CFURLRef versionedBundleURL = + CFURLCreateCopyAppendingPathComponent( + NULL, versURL, bundleVersionRef, TRUE); + + if (versionedBundleURL) { + versionedBundleRef = CFBundleCreate(NULL, + versionedBundleURL); + if (versionedBundleRef) { + bundleRef = versionedBundleRef; + } + CFRelease(versionedBundleURL); + } + CFRelease(versURL); + } + } + CFRelease(bundleVersionRef); } CFRelease(bundleURL); } - CFRelease(bundleVersionRef); - if (versionedBundleURL) { - versionedBundleRef = CFBundleCreate(NULL, versionedBundleURL); - CFRelease(versionedBundleURL); - } - bundleRef = versionedBundleRef; } - if (bundleRef) { + if (bundleRef) { if (hasResourceFile) { - /* Dynamically acquire address for CFBundleOpenBundleResourceMap - * symbol, since it is only present in full CoreFoundation - * on Mac OS X and not in CFLite on pure Darwin. */ - static int initialized = FALSE; - static short (*openresourcemap)(CFBundleRef) = NULL; - if(!initialized) { - NSSymbol nsSymbol = NULL; - if(NSIsSymbolNameDefinedWithHint("_CFBundleOpenBundleResourceMap", "CoreFoundation")) { - nsSymbol = NSLookupAndBindSymbolWithHint("_CFBundleOpenBundleResourceMap", "CoreFoundation"); - if(nsSymbol) { - openresourcemap = NSAddressOfSymbol(nsSymbol); - } - } - initialized = TRUE; - } - if (openresourcemap) { - short refNum; - refNum = openresourcemap(bundleRef); - } + (void) OpenResourceMap(bundleRef); } - libURL = CFBundleCopyResourceURL(bundleRef, - CFSTR("Scripts"), NULL, NULL); + libURL = CFBundleCopyResourceURL(bundleRef, CFSTR("Scripts"), + NULL, NULL); if (libURL) { /* - * FIXME: This is a quick fix, it is probably not right - * for internationalization. + * FIXME: This is a quick fix, it is probably not right for + * internationalization. */ CFURLGetFileSystemRepresentation(libURL, TRUE, - (unsigned char*) libraryPath, maxPathLen); + (unsigned char *) libraryPath, maxPathLen); CFRelease(libURL); } + if (versionedBundleRef) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 + /* + * Workaround CFBundle bug in Tiger and earlier. [Bug 2569449] + */ + + if (tclMacOSXDarwinRelease >= 9) +#endif + { + CFRelease(versionedBundleRef); + } + } } - + if (libraryPath[0]) { - return TCL_OK; - } else { - return TCL_ERROR; + return TCL_OK; } -#else /* HAVE_COREFOUNDATION */ - return TCL_ERROR; #endif /* HAVE_COREFOUNDATION */ + return TCL_ERROR; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |