// 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 NSKeyedUnarchiver : NSCoder {
    struct UnarchiverFlags : OptionSet {
        let rawValue : UInt
        
        init(rawValue : UInt) {
            self.rawValue = rawValue
        }
        
        static let None = UnarchiverFlags(rawValue: 0)
        static let FinishedDecoding = UnarchiverFlags(rawValue : 1)
        static let RequiresSecureCoding = UnarchiverFlags(rawValue: 2)
    }
    
    class DecodingContext {
        fileprivate var dict : Dictionary<String, Any>
        fileprivate var genericKey : UInt = 0
        
        init(_ dict : Dictionary<String, Any>) {
            self.dict = dict
        }
    }
    
    private static var _classNameMap : Dictionary<String, AnyClass> = [:]
    private static var _classNameMapLock = Lock()
    
    public weak var delegate: NSKeyedUnarchiverDelegate?
    
    private enum Stream {
        case data(Data)
        case stream(InputStream)
    }
    
    private var _stream : Stream
    private var _flags = UnarchiverFlags(rawValue: 0)
    private var _containers : Array<DecodingContext>? = nil
    private var _objects : Array<Any> = []
    private var _objRefMap : Dictionary<UInt32, AnyObject> = [:]
    private var _replacementMap : Dictionary<NSUniqueObject, AnyObject> = [:]
    private var _classNameMap : Dictionary<String, AnyClass> = [:]
    private var _classes : Dictionary<UInt32, AnyClass> = [:]
    private var _cache : Array<CFKeyedArchiverUID> = []
    private var _allowedClasses : Array<[AnyClass]> = []
    private var _error : NSError? = nil
    
    internal override var error: NSError? {
        return _error
    }
    
    public class func unarchiveObjectWithData(_ data: Data) -> AnyObject? {
        do {
            return try unarchiveTopLevelObjectWithData(data)
        } catch {
        }
        return nil
    }
    
    public class func unarchiveObjectWithFile(_ path: String) -> AnyObject? {
        let url = URL(fileURLWithPath: path)
        let readStream = CFReadStreamCreateWithFile(kCFAllocatorSystemDefault, url._cfObject)!
        var root : AnyObject? = nil
        
        if !CFReadStreamOpen(readStream) {
            return nil
        }
        
        let keyedUnarchiver = NSKeyedUnarchiver(stream: Stream.stream(unsafeBitCast(readStream, to: InputStream.self)))
        do {
            try root = keyedUnarchiver.decodeTopLevelObjectForKey(NSKeyedArchiveRootObjectKey)
            keyedUnarchiver.finishDecoding()
        } catch {
        }
        
        CFReadStreamClose(readStream)
        
        return root
    }
    
    public convenience init(forReadingWithData data: Data) {
        self.init(stream: Stream.data(data))
    }
    
    private init(stream: Stream) {
        self._stream = stream
        super.init()
        
        do {
            try _readPropertyList()
        } catch let error as NSError {
            failWithError(error)
        } catch {
        }
    }
  
    private func _readPropertyList() throws {
        var plist : Any? = nil
        var format = PropertyListSerialization.PropertyListFormat.binary
        
        // FIXME this implementation reads the entire property list into memory
        // which will not scale for large archives. We should support incremental
        // unarchiving, but that will be a considerable amount of work.
        
        switch self._stream {
        case .data(let data):
            try plist = PropertyListSerialization.propertyList(from: data, options: PropertyListSerialization.MutabilityOptions.immutable, format: &format)
            break
        case .stream(let inputStream):
            try plist = PropertyListSerialization.propertyListWithStream(unsafeBitCast(inputStream, to: CFReadStream.self),
                                                                           length: 0,
                                                                           options: PropertyListSerialization.MutabilityOptions.immutable,
                                                                           format: &format)
            break
        }
        
        guard let unwrappedPlist = plist as? Dictionary<String, Any> else {
            throw _decodingError(NSCocoaError.PropertyListReadCorruptError,
                                 withDescription: "Unable to read archive. The data may be corrupt.")
        }
        
        let archiver = unwrappedPlist["$archiver"] as? String
        if archiver != NSStringFromClass(NSKeyedArchiver.self) {
            throw _decodingError(NSCocoaError.PropertyListReadCorruptError,
                                 withDescription: "Unknown archiver. The data may be corrupt.")
        }
        
        let version = unwrappedPlist["$version"] as? NSNumber
        if version?.int32Value != Int32(NSKeyedArchivePlistVersion) {
            throw _decodingError(NSCocoaError.PropertyListReadCorruptError,
                                 withDescription: "Unknown archive version. The data may be corrupt.")
        }
        
        let top = unwrappedPlist["$top"] as? Dictionary<String, Any>
        let objects = unwrappedPlist["$objects"] as? Array<Any>
        
        if top == nil || objects == nil {
            throw _decodingError(NSCocoaError.PropertyListReadCorruptError,
                                 withDescription: "Unable to read archive contents. The data may be corrupt.")
        }
        
        self._objects = objects!
        self._containers = [DecodingContext(top!)]
    }
    
    private func _pushDecodingContext(_ decodingContext: DecodingContext) {
        self._containers!.append(decodingContext)
    }
    
    private func _popDecodingContext() {
        self._containers!.removeLast()
    }
    
    private var _currentDecodingContext : DecodingContext {
        return self._containers!.last!
    }
    
    private func _nextGenericKey() -> String {
        let key = "$" + String(_currentDecodingContext.genericKey)
        _currentDecodingContext.genericKey += 1
        return key
    }
    
    private func _objectInCurrentDecodingContext<T>(forKey key: String?) -> T? {
        var unwrappedKey = key
        
        if key != nil {
            unwrappedKey = escapeArchiverKey(key!)
        } else {
            unwrappedKey = _nextGenericKey()
        }

        return _currentDecodingContext.dict[unwrappedKey!] as? T
    }
    
    /**
        Dereferences, but does not decode, an object reference
     */
    private func _dereferenceObjectReference(_ unwrappedObjectRef: CFKeyedArchiverUID) -> Any? {
        let uid = Int(objectRefGetValue(unwrappedObjectRef))
        
        guard uid < self._objects.count else {
            return nil
        }

        return self._objects[uid]
    }
    
    public override var systemVersion: UInt32 {
        return NSKeyedArchiverSystemVersion
    }
    
    public override var allowsKeyedCoding: Bool {
        get {
            return true
        }
    }
    
    private func _validateStillDecoding() -> Bool {
        if self._flags.contains(UnarchiverFlags.FinishedDecoding) {
            fatalError("Decoder already finished")
        }
        
        return true
    }
    
    private static func _supportsSecureCoding(_ clsv : AnyClass) -> Bool {
        if let secureCodable = clsv as? NSSecureCoding.Type {
            return secureCodable.supportsSecureCoding()
        }
        
        return false
    }
    
    // FIXME is there a better way to do this with Swift stdlib?
    private static func _classIsKindOfClass(_ assertedClass : AnyClass, _ allowedClass : AnyClass) -> Bool {
        var superClass : AnyClass? = assertedClass
        
        repeat {
            if superClass == allowedClass {
                return true
            }
            
            superClass = _getSuperclass(superClass!)
        } while superClass != nil
        
        return false
    }
    
    private func _isClassAllowed(_ assertedClass: AnyClass?, allowedClasses: [AnyClass]?) -> Bool {
        if assertedClass == nil {
            return false
        }
        
        if _flags.contains(UnarchiverFlags.RequiresSecureCoding) {
            if let unwrappedAllowedClasses = allowedClasses {
                if unwrappedAllowedClasses.contains(where: {NSKeyedUnarchiver._classIsKindOfClass(assertedClass!, $0)}) {
                    return true
                }
            }
            
            fatalError("Value was of unexpected class \(assertedClass!)")
        } else {
            return true
        }
    }
   
    /**
        Validate a dictionary with class type information, mapping to a class if allowed
     */ 
    private func _validateAndMapClassDictionary(_ classDict: Dictionary<String, Any>?,
                                                allowedClasses: [AnyClass]?,
                                                classToConstruct: inout AnyClass?) -> Bool {
        classToConstruct = nil
        
        func _classForClassName(_ codedName: String) -> AnyClass? {
            var aClass : AnyClass?
            
            aClass = classForClassName(codedName)
            if aClass == nil {
                aClass = NSKeyedUnarchiver.classForClassName(codedName)
            }
            if aClass == nil {
                aClass = NSClassFromString(codedName)
            }
            
            return aClass
        }
        
        guard let unwrappedClassDict = classDict else {
            return false
        }
        
        // TODO is it required to validate the superclass hierarchy?
        let assertedClassName = unwrappedClassDict["$classname"] as? String
        let assertedClassHints = unwrappedClassDict["$classhints"] as? [String]
        let assertedClasses = unwrappedClassDict["$classes"] as? [String]
        
        if assertedClassName != nil {
            let assertedClass : AnyClass? = _classForClassName(assertedClassName!)
            if _isClassAllowed(assertedClass, allowedClasses: allowedClasses) {
                classToConstruct = assertedClass
                return true
            }
        }
        
        if assertedClassHints != nil {
            for assertedClassHint in assertedClassHints! {
                // FIXME check whether class hints should be subject to mapping or not
                let assertedClass : AnyClass? = NSClassFromString(assertedClassHint)
                if _isClassAllowed(assertedClass, allowedClasses: allowedClasses) {
                    classToConstruct = assertedClass
                    return true
                }
            }
        }
        
        if assertedClassName != nil {
            if let unwrappedDelegate = self.delegate {
                classToConstruct = unwrappedDelegate.unarchiver(self,
                                                                cannotDecodeObjectOfClassName: assertedClassName!,
                                                                originalClasses: assertedClasses != nil ? assertedClasses! : [])
                if classToConstruct != nil {
                    return true
                }
            }
        }
        
        return false
    }
    
    /**
        Validate a class reference against a class list, and return the class object if allowed
     */
    private func _validateAndMapClassReference(_ classReference: CFKeyedArchiverUID,
                                               allowedClasses: [AnyClass]?) throws -> AnyClass? {
        let classUid = objectRefGetValue(classReference)
        var classToConstruct : AnyClass? = _classes[classUid]
 
        if classToConstruct == nil {
            guard let classDict = _dereferenceObjectReference(classReference) as? Dictionary<String, Any> else {
                return nil
            }
            
            if !_validateAndMapClassDictionary(classDict,
                                               allowedClasses: allowedClasses,
                                               classToConstruct: &classToConstruct) {
                throw _decodingError(NSCocoaError.CoderReadCorruptError, withDescription: "Invalid class \(classDict). The data may be corrupt.")
            }
            
            _classes[classUid] = classToConstruct
        }
        
        return classToConstruct
    }
    
    /**
        Returns true if objectOrReference represents a reference to another object in the archive
     */
    internal static func _isReference(_ objectOrReference : Any?) -> Bool {
        if let cf = objectOrReference as? __NSCFType {
            return CFGetTypeID(cf) == _CFKeyedArchiverUIDGetTypeID()
        } else {
            return false
        }
    }
    
    private func _cachedObjectForReference(_ objectRef: CFKeyedArchiverUID) -> AnyObject? {
        return self._objRefMap[objectRefGetValue(objectRef)]
    }
    
    private func _cacheObject(_ object: AnyObject, forReference objectRef: CFKeyedArchiverUID) {
        self._objRefMap[objectRefGetValue(objectRef)] = object
    }
    
    /**
        Returns true if the object is a dictionary representing a object rather than a value type
     */
    private func _isContainer(_ object: Any) -> Bool {
        guard let dict = object as? Dictionary<String, Any> else {
            return false
        }
        
        let classRef = dict["$class"]
        
        return NSKeyedUnarchiver._isReference(classRef)
    }
    
    
    /**
        Replace object with another one
     */
    private func replaceObject(_ object: AnyObject, withObject replacement: AnyObject) {
        let oid = NSUniqueObject(object)
        
        if let unwrappedDelegate = self.delegate {
            unwrappedDelegate.unarchiver(self, willReplace: object, with: replacement)
        }
        
        self._replacementMap[oid] = replacement
    }
    
    private func _decodingError(_ code: NSCocoaError, withDescription description: String) -> NSError {
        return NSError(domain: NSCocoaErrorDomain,
                               code: code.rawValue, userInfo: [ "NSDebugDescription" : description ])
    }
    
    private func _replacementObject(_ decodedObject: AnyObject?) -> AnyObject? {
        var object : AnyObject? = nil // object to encode after substitution
        
        // nil cannot be mapped
        if decodedObject == nil {
            return nil
        }
        
        // check replacement cache
        object = self._replacementMap[NSUniqueObject(decodedObject!)]
        if object != nil {
            return object
        }
        
        // object replaced by delegate. If the delegate returns nil, nil is encoded
        if let unwrappedDelegate = self.delegate {
            object = unwrappedDelegate.unarchiver(self, didDecode: decodedObject!)
            if object != nil {
                replaceObject(decodedObject!, withObject: object!)
                return object
            }
        }
        
        return decodedObject
    }
    
    private func _validateClassSupportsSecureCoding(_ classToConstruct : AnyClass?) -> Bool {
        var supportsSecureCoding : Bool = false
        
        if let secureDecodableClass = classToConstruct as? NSSecureCoding.Type {
            supportsSecureCoding = secureDecodableClass.supportsSecureCoding()
        }
        
        if self.requiresSecureCoding && !supportsSecureCoding {
            // FIXME should this be a fatal error?
            fatalError("Archiver \(self) requires secure coding but class \(classToConstruct) does not support it")
        }
        
        return supportsSecureCoding
    }

    /**
        Decode an object for the given reference
     */
    private func _decodeObject(_ objectRef: AnyObject) throws -> AnyObject? {
        var object : AnyObject? = nil

        let _ = _validateStillDecoding()

        if !NSKeyedUnarchiver._isReference(objectRef) {
            throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                 withDescription: "Object \(objectRef) is not a reference. The data may be corrupt.")
        }

        guard let dereferencedObject = _dereferenceObjectReference(objectRef) else {
            throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                 withDescription: "Invalid object reference \(objectRef). The data may be corrupt.")
        }

        if dereferencedObject as? String == NSKeyedArchiveNullObjectReferenceName {
            return nil
        }

        if _isContainer(dereferencedObject) {
            // check cached of decoded objects
            object = _cachedObjectForReference(objectRef)
            if object == nil {
                guard let dict = dereferencedObject as? Dictionary<String, Any> else {
                    throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                         withDescription: "Invalid object encoding \(objectRef). The data may be corrupt.")
                }

                let innerDecodingContext = DecodingContext(dict)

                let classReference = innerDecodingContext.dict["$class"] as? CFKeyedArchiverUID
                if !NSKeyedUnarchiver._isReference(classReference) {
                    throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                         withDescription: "Invalid class reference \(classReference). The data may be corrupt.")
                }

                var classToConstruct : AnyClass? = try _validateAndMapClassReference(classReference!,
                                                                                     allowedClasses: self.allowedClasses)

                _pushDecodingContext(innerDecodingContext)
                defer { _popDecodingContext() } // ensure an error does not invalidate the decoding context stack

                if let ns = classToConstruct as? NSObject.Type {
                    classToConstruct = ns.classForKeyedUnarchiver()
                }

                guard let decodableClass = classToConstruct as? NSCoding.Type else {
                    throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                         withDescription: "Class \(classToConstruct!) is not decodable. The data may be corrupt.")
                }

                let _ = _validateClassSupportsSecureCoding(classToConstruct)

                object = decodableClass.init(coder: self) as? AnyObject
                guard object != nil else {
                    throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                         withDescription: "Class \(classToConstruct!) failed to decode. The data may be corrupt.")
                }

                _cacheObject(object!, forReference: objectRef)
            }
        } else {
            // reference to a non-container object
            // FIXME remove these special cases
            if let str = dereferencedObject as? String {
                object = str.bridge()
            } else {
                object = dereferencedObject as? AnyObject
            }
        }

        return _replacementObject(object)
    }

    /**
            Internal function to decode an object. Returns the decoded object or throws an error.
     */
    private func _decodeObject(forKey key: String?) throws -> AnyObject? {
        guard let objectRef : AnyObject? = _objectInCurrentDecodingContext(forKey: key) else {
            throw _decodingError(NSCocoaError.CoderValueNotFoundError,
                                 withDescription: "No value found for key \(key). The data may be corrupt.")
        }
        
        return try _decodeObject(objectRef!)
    }

    /**
        Decode a value type in the current decoding context
     */
    internal func _decodeValue<T>(forKey key: String? = nil) -> T? {
        let _ = _validateStillDecoding()
        return _objectInCurrentDecodingContext(forKey: key)
    }

    /**
        Helper for NSArray/NSDictionary to dereference and decode an array of objects
     */
    internal func _decodeArrayOfObjectsForKey(_ key: String,
                                              withBlock block: @noescape (Any) -> Void) throws {
        let objectRefs : Array<Any>? = _decodeValue(forKey: key)
        
        guard let unwrappedObjectRefs = objectRefs else {
            return
        }
        
        for objectRef in unwrappedObjectRefs {
            guard NSKeyedUnarchiver._isReference(objectRef) else {
                return
            }
            
            if let object = try _decodeObject(objectRef as! CFKeyedArchiverUID) {
                block(object)
            }
        }
    }
    
    internal override func _decodeArrayOfObjectsForKey(_ key: String) -> [AnyObject] {
        var array : Array<AnyObject> = []
        
        do {
            try _decodeArrayOfObjectsForKey(key) { any in
                if let object = any as? AnyObject {
                    array.append(object)
                }
            }
        } catch let error as NSError {
            failWithError(error)
            self._error = error
        } catch {
        }
        
        return array
    }

    /**
     Called when the caller has finished decoding.
     */
    public func finishDecoding() {
        if _flags.contains(UnarchiverFlags.FinishedDecoding) {
            return
        }

        if let unwrappedDelegate = self.delegate {
            unwrappedDelegate.unarchiverWillFinish(self)
        }

        // FIXME are we supposed to do anything here?

        if let unwrappedDelegate = self.delegate {
            unwrappedDelegate.unarchiverDidFinish(self)
        }

        let _ = self._flags.insert(UnarchiverFlags.FinishedDecoding)
    }

    public class func setClass(_ cls: AnyClass?, forClassName codedName: String) {
        _classNameMapLock.synchronized {
            _classNameMap[codedName] = cls
        }
    }
    
    public func setClass(_ cls: AnyClass?, forClassName codedName: String) {
        _classNameMap[codedName] = cls
    }
    
    // During decoding, the coder first checks with the coder's
    // own table, then if there was no mapping there, the class's.
    
    public class func classForClassName(_ codedName: String) -> AnyClass? {
        var mappedClass : AnyClass?
        
        _classNameMapLock.synchronized {
            mappedClass = _classNameMap[codedName]
        }
        
        return mappedClass
    }
    
    public func classForClassName(_ codedName: String) -> AnyClass? {
        return _classNameMap[codedName]
    }
    
    public override func containsValue(forKey key: String) -> Bool {
        let any : Any? = _decodeValue(forKey: key)
        return any != nil
    }
    
    public override func decodeObject(forKey key: String) -> AnyObject? {
        do {
            return try _decodeObject(forKey: key)
        } catch let error as NSError {
            failWithError(error)
            self._error = error
        } catch {
        }
        return nil
    }
    
    // private variant of decodeObjectOfClasses() that supports generic (unkeyed) objects
    private func _decodeObjectOfClasses(_ classes: [AnyClass], forKey key: String? = nil) -> AnyObject? {
        do {
            self._allowedClasses.append(classes)
            defer { self._allowedClasses.removeLast() }
            
            return try _decodeObject(forKey: key)
        } catch let error as NSError {
            failWithError(error)
            self._error = error
        } catch {
        }
        
        return nil
    }

    public override func decodeObjectOfClass<DecodedObjectType : NSCoding where DecodedObjectType : NSObject>(_ cls: DecodedObjectType.Type, forKey key: String) -> DecodedObjectType? {
        return decodeObjectOfClasses([cls], forKey: key) as? DecodedObjectType
    }
    
    public override func decodeObjectOfClasses(_ classes: [AnyClass], forKey key: String) -> AnyObject? {
        return _decodeObjectOfClasses(classes, forKey: key)
    }
    
    public override func decodeTopLevelObjectForKey(_ key: String) throws -> AnyObject? {
        return try decodeTopLevelObjectOfClasses([NSArray.self], forKey: key)
    }
    
    public override func decodeTopLevelObjectOfClass<DecodedObjectType : NSCoding where DecodedObjectType : NSObject>(_ cls: DecodedObjectType.Type, forKey key: String) throws -> DecodedObjectType? {
        return try self.decodeTopLevelObjectOfClasses([cls], forKey: key) as! DecodedObjectType?
    }
    
    public override func decodeTopLevelObjectOfClasses(_ classes: [AnyClass], forKey key: String) throws -> AnyObject? {
        guard self._containers?.count == 1 else {
            throw _decodingError(NSCocoaError.CoderReadCorruptError,
                                 withDescription: "Can only call decodeTopLevelObjectOfClasses when decoding top level objects.")
        }
        
        return decodeObjectOfClasses(classes, forKey: key)
    }
    
    public override func decodeObject() -> AnyObject? {
        do {
            return try _decodeObject(forKey: nil)
        } catch let error as NSError {
            failWithError(error)
            self._error = error
        } catch {
        }
        
        return nil
    }
    
    public override func decodePropertyList() -> AnyObject? {
        return _decodeObjectOfClasses(NSPropertyListClasses)
    }
    
    public override func decodePropertyListForKey(_ key: String) -> AnyObject? {
        return decodeObjectOfClasses(NSPropertyListClasses, forKey:key)
    }
    
    /**
        Note that unlike decodePropertyListForKey(), _decodePropertyListForKey() decodes
        a property list in the current decoding context rather than as an object. It's
        also able to return value types.
     */
    internal override func _decodePropertyListForKey(_ key: String) -> Any {
        return _decodeValue(forKey: key)!
    }
    
    public override func decodeBool(forKey key: String) -> Bool {
        guard let result : NSNumber = _decodeValue(forKey: key) else {
            return false
        }
        return result.boolValue
    }
    
    public override func decodeInt32(forKey key: String) -> Int32 {
        guard let result : NSNumber = _decodeValue(forKey: key) else {
            return 0
        }
        return result.int32Value
    }
    
    public override func decodeInt64(forKey key: String) -> Int64 {
        guard let result : NSNumber = _decodeValue(forKey: key) else {
            return 0
        }
        return result.int64Value
    }
    
    public override func decodeFloat(forKey key: String) -> Float {
        guard let result : NSNumber = _decodeValue(forKey: key) else {
            return 0
        }
        return result.floatValue
    }
    
    public override func decodeDouble(forKey key: String) -> Double {
        guard let result : NSNumber = _decodeValue(forKey: key) else {
            return 0
        }
        return result.doubleValue
    }
    
    public override func decodeInteger(forKey key: String) -> Int {
        guard let result : NSNumber = _decodeValue(forKey: key) else {
            return 0
        }
        return result.intValue
    }
    
    /// - experimental: replaces decodeBytes(forKey:)
    public override func withDecodedUnsafeBufferPointer<ResultType>(forKey key: String, body: @noescape (UnsafeBufferPointer<UInt8>?) throws -> ResultType) rethrows -> ResultType {
        let ns : Data? = _decodeValue(forKey: key)
        if let value = ns {
            return try value.withUnsafeBytes {
                try body(UnsafeBufferPointer(start: $0, count: value.count))
            }
        } else {
            return try body(nil)
        }
    }
    
    public override func decodeDataObject() -> Data? {
        return decodeObject() as? Data
    }
    
    private func _decodeValueOfObjCType(_ type: _NSSimpleObjCType, at addr: UnsafeMutableRawPointer) {
        switch type {
        case .ID:
            if let ns = decodeObject() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<AnyObject>.self).pointee = ns
            }
            break
        case .Class:
            if let ns = decodeObject() as? NSString {
                if let nsClass = NSClassFromString(ns.bridge()) {
                    unsafeBitCast(addr, to: UnsafeMutablePointer<AnyClass>.self).pointee = nsClass
                }
            }
            break
        case .Char:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<CChar>.self).pointee = ns.int8Value
            }
            break
        case .UChar:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<UInt8>.self).pointee = ns.uint8Value
            }
            break
        case .Int, .Long:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<Int32>.self).pointee = ns.int32Value
            }
            break
        case .UInt, .ULong:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<UInt32>.self).pointee = ns.uint32Value
            }
            break
        case .LongLong:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<Int64>.self).pointee = ns.int64Value
            }
            break
        case .ULongLong:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<UInt64>.self).pointee = ns.uint64Value
            }
            break
        case .Float:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<Float>.self).pointee = ns.floatValue
            }
            break
        case .Double:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<Double>.self).pointee = ns.doubleValue
            }
            break
        case .Bool:
            if let ns : NSNumber = _decodeValue() {
                unsafeBitCast(addr, to: UnsafeMutablePointer<Bool>.self).pointee = ns.boolValue
            }
            break
        case .CharPtr:
            if let ns = decodeObject() as? NSString {
                let string = ns.utf8String! // XXX leaky
                unsafeBitCast(addr, to: UnsafeMutablePointer<UnsafePointer<Int8>>.self).pointee = string
            }
            break
        default:
            fatalError("NSKeyedUnarchiver.decodeValueOfObjCType: unknown type encoding ('\(type.rawValue)')")
            break
        }
    }
    
    public override func decodeValue(ofObjCType typep: UnsafePointer<Int8>, at addr: UnsafeMutableRawPointer) {
        guard let type = _NSSimpleObjCType(UInt8(typep.pointee)) else {
            let spec = String(typep.pointee)
            fatalError("NSKeyedUnarchiver.decodeValueOfObjCType: unsupported type encoding spec '\(spec)'")
        }
        
        if type == .StructBegin {
            fatalError("NSKeyedUnarchiver.decodeValueOfObjCType: this archiver cannot decode structs")
        } else if type == .ArrayBegin {
            let scanner = Scanner(string: String(cString: typep))
            
            scanner.scanLocation = 1
            
            var count : Int = 0
            guard scanner.scanInteger(&count) && count > 0 else {
                fatalError("NSKeyedUnarchiver.decodeValueOfObjCType: array count is missing or zero")
            }
            
            guard let elementType = _NSSimpleObjCType(scanner.scanUpToString(String(_NSSimpleObjCType.ArrayEnd))) else {
                fatalError("NSKeyedUnarchiver.decodeValueOfObjCType: array type is missing")
            }
            
            if let oldStyleArray = _decodeObjectOfClasses([_NSKeyedCoderOldStyleArray.self]) as? _NSKeyedCoderOldStyleArray {
                oldStyleArray.fillObjCType(elementType, count: count, at: addr)
            }
        } else {
            return _decodeValueOfObjCType(type, at: addr)
        }
    }

    public override var allowedClasses: [AnyClass]? {
        get {
            return self._allowedClasses.last
        }
    }
 
    // Enables secure coding support on this keyed unarchiver. When enabled, anarchiving a disallowed class throws an exception. Once enabled, attempting to set requiresSecureCoding to NO will throw an exception. This is to prevent classes from selectively turning secure coding off. This is designed to be set once at the top level and remain on. Note that the getter is on the superclass, NSCoder. See NSCoder for more information about secure coding.
    public override var requiresSecureCoding: Bool {
        get {
            return _flags.contains(UnarchiverFlags.RequiresSecureCoding)
        }
        set {
            if _flags.contains(UnarchiverFlags.RequiresSecureCoding) {
                if !newValue {
                    fatalError("Cannot unset requiresSecureCoding")
                }
            } else {
                if newValue {
                    let _ = _flags.insert(UnarchiverFlags.RequiresSecureCoding)
                }
            }
        }
    }
}

extension NSKeyedUnarchiver {
    public class func unarchiveTopLevelObjectWithData(_ data: Data) throws -> AnyObject? {
        var root : AnyObject? = nil
        
        let keyedUnarchiver = NSKeyedUnarchiver(forReadingWithData: data)
        do {
            try root = keyedUnarchiver.decodeTopLevelObjectForKey(NSKeyedArchiveRootObjectKey)
            keyedUnarchiver.finishDecoding()
        } catch {
        }
        
        return root
    }
}

public protocol NSKeyedUnarchiverDelegate : class {
    
    // Informs the delegate that the named class is not available during decoding.
    // The delegate may, for example, load some code to introduce the class to the
    // runtime and return it, or substitute a different class object.  If the
    // delegate returns nil, unarchiving aborts with an exception.  The first class
    // name string in the array is the class of the encoded object, the second is
    // the immediate superclass, and so on.
    func unarchiver(_ unarchiver: NSKeyedUnarchiver, cannotDecodeObjectOfClassName name: String, originalClasses classNames: [String]) -> AnyClass?
    
    // Informs the delegate that the object has been decoded.  The delegate
    // either returns this object or can return a different object to replace
    // the decoded one.  The object may be nil.  If the delegate returns nil,
    // the decoded value will be unchanged (that is, the original object will be
    // decoded). The delegate may use this to keep track of the decoded objects.
    func unarchiver(_ unarchiver: NSKeyedUnarchiver, didDecode object: AnyObject?) -> AnyObject?
    
    // Informs the delegate that the newObject is being substituted for the
    // object. This is also called when the delegate itself is doing/has done
    // the substitution. The delegate may use this method if it is keeping track
    // of the encoded or decoded objects.
    func unarchiver(_ unarchiver: NSKeyedUnarchiver, willReplace object: AnyObject, with newObject: AnyObject)
    
    // Notifies the delegate that decoding is about to finish.
    func unarchiverWillFinish(_ unarchiver: NSKeyedUnarchiver)
    
    // Notifies the delegate that decoding has finished.
    func unarchiverDidFinish(_ unarchiver: NSKeyedUnarchiver)
}

extension NSKeyedUnarchiverDelegate {
    func unarchiver(_ unarchiver: NSKeyedUnarchiver, cannotDecodeObjectOfClassName name: String, originalClasses classNames: [String]) -> AnyClass? {
        return nil
    }
    
    func unarchiver(_ unarchiver: NSKeyedUnarchiver, didDecode object: AnyObject?) -> AnyObject? {
        // Returning the same object is the same as doing nothing
        return object
    }
    
    func unarchiver(_ unarchiver: NSKeyedUnarchiver, willReplace object: AnyObject, with newObject: AnyObject) { }
    func unarchiverWillFinish(_ unarchiver: NSKeyedUnarchiver) { }
    func unarchiverDidFinish(_ unarchiver: NSKeyedUnarchiver) { }
}
