blob: f1a1e2e5a9e80c358ebb02bdf28efa65dadcfd5b [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
import CoreFoundation
public class NSBundle : NSObject {
private var _bundle : CFBundle!
private static var _mainBundle : NSBundle = {
return NSBundle(cfBundle: CFBundleGetMainBundle())
}()
public class func mainBundle() -> NSBundle {
return _mainBundle
}
internal init(cfBundle: CFBundle) {
super.init()
_bundle = cfBundle
}
public init?(path: String) {
super.init()
// TODO: We do not yet resolve symlinks, but we must for compatibility
// let resolvedPath = path._nsObject.stringByResolvingSymlinksInPath
let resolvedPath = path
guard resolvedPath.length > 0 else {
return nil
}
let url = NSURL(fileURLWithPath: resolvedPath)
_bundle = CFBundleCreate(kCFAllocatorSystemDefault, unsafeBitCast(url, to: CFURL.self))
}
public convenience init?(URL url: NSURL) {
if let path = url.path {
self.init(path: path)
} else {
return nil
}
}
public init(forClass aClass: AnyClass) { NSUnimplemented() }
public init?(identifier: String) {
super.init()
guard let result = CFBundleGetBundleWithIdentifier(identifier._cfObject) else {
return nil
}
_bundle = result
}
/* Methods for loading and unloading bundles. */
public func load() -> Bool { NSUnimplemented() }
public var loaded: Bool { NSUnimplemented() }
public func unload() -> Bool { NSUnimplemented() }
public func preflight() throws { NSUnimplemented() }
public func loadAndReturnError() throws { NSUnimplemented() }
/* Methods for locating various components of a bundle. */
public var bundleURL: NSURL {
return CFBundleCopyBundleURL(_bundle)._nsObject
}
public var resourceURL: NSURL? {
return CFBundleCopyResourcesDirectoryURL(_bundle)?._nsObject
}
public var executableURL: NSURL? {
return CFBundleCopyExecutableURL(_bundle)?._nsObject
}
public func URLForAuxiliaryExecutable(_ executableName: String) -> NSURL? {
return CFBundleCopyAuxiliaryExecutableURL(_bundle, executableName._cfObject)?._nsObject
}
public var privateFrameworksURL: NSURL? {
return CFBundleCopyPrivateFrameworksURL(_bundle)?._nsObject
}
public var sharedFrameworksURL: NSURL? {
return CFBundleCopySharedFrameworksURL(_bundle)?._nsObject
}
public var sharedSupportURL: NSURL? {
return CFBundleCopySharedSupportURL(_bundle)?._nsObject
}
public var builtInPlugInsURL: NSURL? {
return CFBundleCopyBuiltInPlugInsURL(_bundle)?._nsObject
}
public var appStoreReceiptURL: NSURL? {
// Always nil on this platform
return nil
}
public var bundlePath: String {
return bundleURL.path!
}
public var resourcePath: String? {
return resourceURL?.path
}
public var executablePath: String? {
return executableURL?.path
}
public func pathForAuxiliaryExecutable(_ executableName: String) -> String? {
return URLForAuxiliaryExecutable(executableName)?.path
}
public var privateFrameworksPath: String? {
return privateFrameworksURL?.path
}
public var sharedFrameworksPath: String? {
return sharedFrameworksURL?.path
}
public var sharedSupportPath: String? {
return sharedSupportURL?.path
}
public var builtInPlugInsPath: String? {
return builtInPlugInsURL?.path
}
// -----------------------------------------------------------------------------------
// MARK: - URL Resource Lookup - Class
public class func URLForResource(_ name: String?, withExtension ext: String?, subdirectory subpath: String?, inBundleWithURL bundleURL: NSURL) -> NSURL? {
// If both name and ext are nil/zero-length, return nil
if (name == nil || name!.isEmpty) && (ext == nil || ext!.isEmpty) {
return nil
}
return CFBundleCopyResourceURLInDirectory(bundleURL._cfObject, name?._cfObject, ext?._cfObject, subpath?._cfObject)._nsObject
}
public class func URLsForResourcesWithExtension(_ ext: String?, subdirectory subpath: String?, inBundleWithURL bundleURL: NSURL) -> [NSURL]? {
return CFBundleCopyResourceURLsOfTypeInDirectory(bundleURL._cfObject, ext?._cfObject, subpath?._cfObject)?._unsafeTypedBridge()
}
// -----------------------------------------------------------------------------------
// MARK: - URL Resource Lookup - Instance
public func URLForResource(_ name: String?, withExtension ext: String?) -> NSURL? {
return self.URLForResource(name, withExtension: ext, subdirectory: nil)
}
public func URLForResource(_ name: String?, withExtension ext: String?, subdirectory subpath: String?) -> NSURL? {
// If both name and ext are nil/zero-length, return nil
if (name == nil || name!.isEmpty) && (ext == nil || ext!.isEmpty) {
return nil
}
return CFBundleCopyResourceURL(_bundle, name?._cfObject, ext?._cfObject, subpath?._cfObject)?._nsObject
}
public func URLForResource(_ name: String?, withExtension ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> NSURL? {
// If both name and ext are nil/zero-length, return nil
if (name == nil || name!.isEmpty) && (ext == nil || ext!.isEmpty) {
return nil
}
return CFBundleCopyResourceURLForLocalization(_bundle, name?._cfObject, ext?._cfObject, subpath?._cfObject, localizationName?._cfObject)?._nsObject
}
public func URLsForResourcesWithExtension(_ ext: String?, subdirectory subpath: String?) -> [NSURL]? {
return CFBundleCopyResourceURLsOfType(_bundle, ext?._cfObject, subpath?._cfObject)?._unsafeTypedBridge()
}
public func URLsForResourcesWithExtension(_ ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> [NSURL]? {
return CFBundleCopyResourceURLsOfTypeForLocalization(_bundle, ext?._cfObject, subpath?._cfObject, localizationName?._cfObject)?._unsafeTypedBridge()
}
// -----------------------------------------------------------------------------------
// MARK: - Path Resource Lookup - Class
public class func pathForResource(_ name: String?, ofType ext: String?, inDirectory bundlePath: String) -> String? {
return NSBundle.URLForResource(name, withExtension: ext, subdirectory: bundlePath, inBundleWithURL: NSURL(fileURLWithPath: bundlePath))?.path ?? nil
}
public class func pathsForResourcesOfType(_ ext: String?, inDirectory bundlePath: String) -> [String] {
// Force-unwrap path, beacuse if the URL can't be turned into a path then something is wrong anyway
return URLsForResourcesWithExtension(ext, subdirectory: bundlePath, inBundleWithURL: NSURL(fileURLWithPath: bundlePath))?.map { $0.path! } ?? []
}
// -----------------------------------------------------------------------------------
// MARK: - Path Resource Lookup - Instance
public func pathForResource(_ name: String?, ofType ext: String?) -> String? {
return self.URLForResource(name, withExtension: ext, subdirectory: nil)?.path
}
public func pathForResource(_ name: String?, ofType ext: String?, inDirectory subpath: String?) -> String? {
return self.URLForResource(name, withExtension: ext, subdirectory: subpath)?.path
}
public func pathForResource(_ name: String?, ofType ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> String? {
return self.URLForResource(name, withExtension: ext, subdirectory: subpath, localization: localizationName)?.path
}
public func pathsForResourcesOfType(_ ext: String?, inDirectory subpath: String?) -> [String] {
// Force-unwrap path, beacuse if the URL can't be turned into a path then something is wrong anyway
return self.URLsForResourcesWithExtension(ext, subdirectory: subpath)?.map { $0.path! } ?? []
}
public func pathsForResourcesOfType(_ ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> [String] {
// Force-unwrap path, beacuse if the URL can't be turned into a path then something is wrong anyway
return self.URLsForResourcesWithExtension(ext, subdirectory: subpath, localization: localizationName)?.map { $0.path! } ?? []
}
// -----------------------------------------------------------------------------------
// MARK: - Localized Strings
public func localizedStringForKey(_ key: String, value: String?, table tableName: String?) -> String {
let localizedString = CFBundleCopyLocalizedString(_bundle, key._cfObject, value?._cfObject, tableName?._cfObject)!
return localizedString._swiftObject
}
// -----------------------------------------------------------------------------------
// MARK: - Other
public var bundleIdentifier: String? {
return CFBundleGetIdentifier(_bundle)?._swiftObject
}
/// - Experiment: This is a draft API currently under consideration for official import into Foundation
/// - Note: This API differs from Darwin because it uses [String : Any] as a type instead of [String : AnyObject]. This allows the use of Swift value types.
public var infoDictionary: [String : Any]? {
let cfDict: CFDictionary? = CFBundleGetInfoDictionary(_bundle)
return cfDict.map(_expensivePropertyListConversion) as? [String: Any]
}
/// - Experiment: This is a draft API currently under consideration for official import into Foundation
/// - Note: This API differs from Darwin because it uses [String : Any] as a type instead of [String : AnyObject]. This allows the use of Swift value types.
public var localizedInfoDictionary: [String : Any]? {
let cfDict: CFDictionary? = CFBundleGetLocalInfoDictionary(_bundle)
return cfDict.map(_expensivePropertyListConversion) as? [String: Any]
}
/// - Experiment: This is a draft API currently under consideration for official import into Foundation
/// - Note: This API differs from Darwin because it uses [String : Any] as a type instead of [String : AnyObject]. This allows the use of Swift value types.
public func objectForInfoDictionaryKey(_ key: String) -> Any? {
if let localizedInfoDictionary = localizedInfoDictionary {
return localizedInfoDictionary[key]
} else {
return infoDictionary?[key]
}
}
public func classNamed(_ className: String) -> AnyClass? { NSUnimplemented() }
public var principalClass: AnyClass? { NSUnimplemented() }
public var preferredLocalizations: [String] {
return NSBundle.preferredLocalizationsFromArray(localizations)
}
public var localizations: [String] {
let cfLocalizations: CFArray? = CFBundleCopyBundleLocalizations(_bundle)
let nsLocalizations = cfLocalizations.map(_expensivePropertyListConversion) as? [Any]
return nsLocalizations?.map { $0 as! String } ?? []
}
public var developmentLocalization: String? {
let region = CFBundleGetDevelopmentRegion(_bundle)!
return region._swiftObject
}
public class func preferredLocalizationsFromArray(_ localizationsArray: [String]) -> [String] {
let cfLocalizations: CFArray? = CFBundleCopyPreferredLocalizationsFromArray(localizationsArray._cfObject)
let nsLocalizations = cfLocalizations.map(_expensivePropertyListConversion) as? [Any]
return nsLocalizations?.map { $0 as! String } ?? []
}
public class func preferredLocalizationsFromArray(_ localizationsArray: [String], forPreferences preferencesArray: [String]?) -> [String] {
let localizations = CFBundleCopyLocalizationsForPreferences(localizationsArray._cfObject, preferencesArray?._cfObject)!
return localizations._swiftObject.map { return ($0 as! NSString)._swiftObject }
}
public var executableArchitectures: [NSNumber]? {
let architectures = CFBundleCopyExecutableArchitectures(_bundle)!
return architectures._swiftObject.map() { $0 as! NSNumber }
}
}