sl@0: /* sl@0: * tclMacOSXBundle.c -- sl@0: * sl@0: * This file implements functions that inspect CFBundle structures on sl@0: * MacOS X. sl@0: * sl@0: * Copyright 2001, Apple Computer, Inc. sl@0: * Copyright (c) 2003-2007 Daniel A. Steffen sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution of sl@0: * this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * The following terms apply to all files originating from Apple sl@0: * Computer, Inc. ("Apple") and associated with the software unless sl@0: * explicitly disclaimed in individual files. sl@0: * sl@0: * Apple hereby grants permission to use, copy, modify, distribute, and sl@0: * license this software and its documentation for any purpose, provided sl@0: * that existing copyright notices are retained in all copies and that sl@0: * this notice is included verbatim in any distributions. No written sl@0: * agreement, license, or royalty fee is required for any of the sl@0: * authorized uses. Modifications to this software may be copyrighted by sl@0: * their authors and need not follow the licensing terms described here, sl@0: * provided that the new terms are clearly indicated on the first page of sl@0: * each file where they apply. sl@0: * sl@0: * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE SOFTWARE sl@0: * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR sl@0: * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS sl@0: * DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF APPLE OR THE sl@0: * AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. APPLE, sl@0: * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, sl@0: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF sl@0: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND sl@0: * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND sl@0: * APPLE,THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE sl@0: * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. sl@0: * sl@0: * GOVERNMENT USE: If you are acquiring this software on behalf of the sl@0: * U.S. government, the Government shall have only "Restricted Rights" in sl@0: * the software and related documentation as defined in the Federal sl@0: * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are sl@0: * acquiring the software on behalf of the Department of Defense, the sl@0: * software shall be classified as "Commercial Computer Software" and the sl@0: * Government shall have only "Restricted Rights" as defined in Clause sl@0: * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the sl@0: * authors grant the U.S. Government and others acting in its behalf sl@0: * permission to use and distribute the software in accordance with the sl@0: * terms specified in this license. sl@0: * sl@0: * RCS: @(#) $Id: tclMacOSXBundle.c,v 1.3.2.6 2007/04/29 02:21:33 das Exp $ sl@0: */ sl@0: sl@0: #include "tclPort.h" sl@0: sl@0: #ifdef HAVE_COREFOUNDATION sl@0: #include sl@0: #include sl@0: #endif /* HAVE_COREFOUNDATION */ sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * Tcl_MacOSXOpenBundleResources -- sl@0: * sl@0: * Given the bundle name for a shared library, this routine sets sl@0: * libraryPath to the Resources/Scripts directory in the framework sl@0: * package. If hasResourceFile is true, it will also open the main sl@0: * resource file for the bundle. sl@0: * sl@0: * Results: sl@0: * TCL_OK if the bundle could be opened, and the Scripts folder found. sl@0: * TCL_ERROR otherwise. sl@0: * sl@0: * Side effects: sl@0: * libraryVariableName may be set, and the resource file opened. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: Tcl_MacOSXOpenBundleResources( sl@0: Tcl_Interp *interp, sl@0: CONST char *bundleName, sl@0: int hasResourceFile, sl@0: int maxPathLen, sl@0: char *libraryPath) sl@0: { sl@0: return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, sl@0: NULL, hasResourceFile, maxPathLen, libraryPath); sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * Tcl_MacOSXOpenVersionedBundleResources -- sl@0: * sl@0: * Given the bundle and version name for a shared library (version name sl@0: * can be NULL to indicate latest version), this routine sets libraryPath sl@0: * to the Resources/Scripts directory in the framework package. If sl@0: * hasResourceFile is true, it will also open the main resource file for sl@0: * the bundle. sl@0: * sl@0: * Results: sl@0: * TCL_OK if the bundle could be opened, and the Scripts folder found. sl@0: * TCL_ERROR otherwise. sl@0: * sl@0: * Side effects: sl@0: * libraryVariableName may be set, and the resource file opened. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: Tcl_MacOSXOpenVersionedBundleResources( sl@0: Tcl_Interp *interp, sl@0: CONST char *bundleName, sl@0: CONST char *bundleVersion, sl@0: int hasResourceFile, sl@0: int maxPathLen, sl@0: char *libraryPath) sl@0: { sl@0: #ifdef HAVE_COREFOUNDATION sl@0: CFBundleRef bundleRef; sl@0: CFStringRef bundleNameRef; sl@0: CFURLRef libURL; sl@0: sl@0: libraryPath[0] = '\0'; sl@0: sl@0: bundleNameRef = CFStringCreateWithCString(NULL, bundleName, sl@0: kCFStringEncodingUTF8); sl@0: sl@0: bundleRef = CFBundleGetBundleWithIdentifier(bundleNameRef); sl@0: CFRelease(bundleNameRef); sl@0: sl@0: if (bundleVersion && bundleRef) { sl@0: /* sl@0: * Create bundle from bundleVersion subdirectory of 'Versions'. sl@0: */ sl@0: sl@0: CFBundleRef versionedBundleRef = NULL; sl@0: CFURLRef versionedBundleURL = NULL; sl@0: CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL, sl@0: bundleVersion, kCFStringEncodingUTF8); sl@0: CFURLRef bundleURL = CFBundleCopyBundleURL(bundleRef); sl@0: sl@0: if (bundleURL) { sl@0: CFStringRef bundleTailRef = CFURLCopyLastPathComponent(bundleURL); sl@0: sl@0: if (bundleTailRef) { sl@0: if (CFStringCompare(bundleTailRef, bundleVersionRef, 0) == sl@0: kCFCompareEqualTo) { sl@0: versionedBundleRef = bundleRef; sl@0: } sl@0: CFRelease(bundleTailRef); sl@0: } sl@0: } sl@0: sl@0: if (bundleURL && !versionedBundleRef) { sl@0: CFURLRef versURL = CFURLCreateCopyAppendingPathComponent(NULL, sl@0: bundleURL, CFSTR("Versions"), TRUE); sl@0: sl@0: if (versURL) { sl@0: versionedBundleURL = CFURLCreateCopyAppendingPathComponent( sl@0: NULL, versURL, bundleVersionRef, TRUE); sl@0: CFRelease(versURL); sl@0: } sl@0: CFRelease(bundleURL); sl@0: } sl@0: CFRelease(bundleVersionRef); sl@0: if (versionedBundleURL) { sl@0: versionedBundleRef = CFBundleCreate(NULL, versionedBundleURL); sl@0: CFRelease(versionedBundleURL); sl@0: } sl@0: bundleRef = versionedBundleRef; sl@0: } sl@0: sl@0: if (bundleRef) { sl@0: if (hasResourceFile) { sl@0: /* sl@0: * Dynamically acquire address for CFBundleOpenBundleResourceMap sl@0: * symbol, since it is only present in full CoreFoundation on Mac sl@0: * OS X and not in CFLite on pure Darwin. sl@0: */ sl@0: sl@0: static int initialized = FALSE; sl@0: static short (*openresourcemap)(CFBundleRef) = NULL; sl@0: sl@0: if (!initialized) { sl@0: NSSymbol nsSymbol = NULL; sl@0: if (NSIsSymbolNameDefinedWithHint( sl@0: "_CFBundleOpenBundleResourceMap", "CoreFoundation")) { sl@0: nsSymbol = NSLookupAndBindSymbolWithHint( sl@0: "_CFBundleOpenBundleResourceMap","CoreFoundation"); sl@0: if (nsSymbol) { sl@0: openresourcemap = NSAddressOfSymbol(nsSymbol); sl@0: } sl@0: } sl@0: initialized = TRUE; sl@0: } sl@0: sl@0: if (openresourcemap) { sl@0: short refNum; sl@0: sl@0: refNum = openresourcemap(bundleRef); sl@0: } sl@0: } sl@0: sl@0: libURL = CFBundleCopyResourceURL(bundleRef, CFSTR("Scripts"), sl@0: NULL, NULL); sl@0: sl@0: if (libURL) { sl@0: /* sl@0: * FIXME: This is a quick fix, it is probably not right for sl@0: * internationalization. sl@0: */ sl@0: sl@0: CFURLGetFileSystemRepresentation(libURL, TRUE, sl@0: (unsigned char*) libraryPath, maxPathLen); sl@0: CFRelease(libURL); sl@0: } sl@0: } sl@0: sl@0: if (libraryPath[0]) { sl@0: return TCL_OK; sl@0: } else { sl@0: return TCL_ERROR; sl@0: } sl@0: #else /* HAVE_COREFOUNDATION */ sl@0: return TCL_ERROR; sl@0: #endif /* HAVE_COREFOUNDATION */ sl@0: }