 
 /**
  Encode, convert UTF16 code to unicode scalar value.
- - parameter u1:
- - parameter u2:
- - returns:
- */
-private func encodeUTF16(u1: unichar, u2: unichar) -> [UInt]? {
+ - parameter first: First one of a surrogate pair.
+ - parameter second: Second one of a surrogate pair.
+ - returns: Unicode scalar value.
+ */
+private func convertToUnicodeScalar(firstOfSurrogatePair u1: unichar, second u2: unichar) -> UInt? {
     // This convert algorithm is based on https://en.wikipedia.org/wiki/UTF-16
     guard u1 > (0b11011000 << 8) else { return nil }
     guard u1 < (0b11011100 << 8) else { return nil }

        }
    }
}

private protocol ContiguousStorage: Sequence {
    func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Iterator.Element>) throws -> R) rethrows -> R
}

extension Array: ContiguousStorage {}
extension ArraySlice: ContiguousStorage {}
extension ContiguousArray: ContiguousStorage {}

public enum HTMLSpecialCharactersError: Error {
    case invalidHexSquence
    case invalidDecimalSquence
    case invalidEscapeSquence
    case invalidBufferSequence
    case notErrorMatchedUnicode(code: unichar)
}

private func hexStream2UnicodeChars<T>(utf16Storage: T) throws -> [unichar] where T: ContiguousStorage, T.Iterator.Element == unichar {
    let utf16: UInt = try utf16Storage.reduce(0) {
        switch $1 {
        case 48...57: return UInt($0) << 4 + UInt($1) - 48
        case 65...70: return UInt($0) << 4 + UInt($1) - 65 + 10
        case 97...102: return UInt($0) << 4 + UInt($1) - 97 + 10
        default: throw HTMLSpecialCharactersError.invalidHexSquence
        }
    }
    if utf16 < UInt(unichar.max) {
        return [unichar(utf16)]
    } else if utf16 < UInt(0x110000) {
        return decodeUnicodeScalar(unicode: utf16)
    } else {
        throw HTMLSpecialCharactersError.invalidDecimalSquence
    }
}

private func decimalStream2UnicodeChars<T>(utf16Storage: T) throws -> [unichar] where T: ContiguousStorage, T.Iterator.Element == unichar {
    let utf16: UInt = try utf16Storage.reduce(0) {
        switch $1 {
        case 48...57: return UInt($0 * 10) + UInt($1) - 48
        default: throw HTMLSpecialCharactersError.invalidDecimalSquence
        }
    }
    if utf16 < UInt(unichar.max) {
        return [unichar(utf16)]
    } else if utf16 < UInt(0x110000) {
        return decodeUnicodeScalar(unicode: utf16)
    } else {
        throw HTMLSpecialCharactersError.invalidDecimalSquence
    }
}

private func matchUnicodeChars<T>(utf16Storage: T) throws -> unichar where T: ContiguousStorage, T.Iterator.Element == unichar {
    return try utf16Storage.withUnsafeBufferPointer {
        guard let unichars = $0.baseAddress else { throw HTMLSpecialCharactersError.invalidEscapeSquence }
        let length = $0.count
        do {
            try getUnescapeTable(length: length)?.forEach({
                if memcmp($0.unescapingCodes, unichars, MemoryLayout<UniChar>.size * length) == 0 {
                    throw HTMLSpecialCharactersError.notErrorMatchedUnicode(code: $0.code)
                }
            })
            throw HTMLSpecialCharactersError.invalidEscapeSquence
        } catch HTMLSpecialCharactersError.notErrorMatchedUnicode(let code) {
            return code
        }
    }
}

internal func bsearch<T, U>(with key: T, from sortedArray: [U], comparator: (T, U) -> Int) -> (U, Int)? {
    var searchCount = 0
    var startIndex = sortedArray.startIndex
    var endIndex = sortedArray.endIndex
    var range = startIndex..<endIndex
    var middle = startIndex.advanced(by: range.count/2)
    repeat {
        range = startIndex..<endIndex
        middle = startIndex.advanced(by: range.count/2)
        searchCount += 1
        let c = comparator(key, sortedArray[middle])
        if c == 1 {
            startIndex = middle
        } else if c == -1 {
            endIndex = middle
        } else if c == 0 {
            return (sortedArray[middle], searchCount)
        } else {
            return nil
        }
    } while range.count > 1
    return nil
}

        var start = 0
        for var i in 0..<length {
            if let result = bsearch(with: (buffer + i).pointee, from: unicodeHtmlEscapeMapForUTF8, comparator: comp) {
                // 2byte character
                let copyLength = i - start
                destinationBuffer.append(buffer + start, length: MemoryLayout<unichar>.size * copyLength)
                let pointer: UnsafeMutablePointer<unichar> = UnsafeMutablePointer(mutating: (result.0.unescapingCodes))
                destinationBuffer.append(pointer, length: MemoryLayout<unichar>.size * result.0.count)
                start = i + 1
            } else if i < length - 1 {
                if let result = convertToUnicodeScalarString(firstOfSurrogatePair: (buffer + i).pointee, second: (buffer + i + 1).pointee) {
                    // 4byte character, surrogate pair.
                    let copyLength = i - start
                    destinationBuffer.append(buffer + start, length: MemoryLayout<unichar>.size * copyLength)
                    let pointer: UnsafeMutablePointer<unichar> = UnsafeMutablePointer(mutating: (result))
