Issue with Unsafepointer<Uint8> in SQLite Project in Swift

Issue with UnsafePointer Uint8 in SQLite project in Swift

This should work:

let address = sqlite3_column_text(statement, 0)
let string = String.fromCString(UnsafePointer<CChar>(address))

Update for Swift 3 (Xcode 8), compare Swift 3: convert a null-terminated UnsafePointer<UInt8> to a string:

let string = String(cString: sqlite3_column_text(statement, 0))

Update:

sqlite3_column_text() returns an implicitly unwrapped optional, and that is why you can pass it to String(cString:) directly.

But according to Column methods, error and NULL handling #41, the return value can be null (in an out-of-memory situation, or if called with a NULL column type). Therefore it is safer to do

if let text = sqlite3_column_text(statement, 0) {
let string = String(cString: text)
// ...
} else {
// sqlite3_column_text() returned NULL
}

SwiftData (SQLite wrapper) broken with Swift 3.0

sqlite3_column_int(statement, index) returns an Int32 and

sqlite3_column_int(statement, index) != 0

is a boolean value, so that makes no sense as the return value if
an (optional) AnyObject is expected. You can wrap the integer into
a NSNumber instead:

func getColumnValue(_ statement: OpaquePointer, index: Int32, type: String) -> AnyObject? {
let val = sqlite3_column_int(statement, index)
return NSNumber(value: val)
}

Another option would be

func getColumnValue(_ statement: OpaquePointer, index: Int32, type: String) -> AnyObject? {
return sqlite3_column_int(statement, index) as AnyObject
}

because in Swift 3, anything can be converted to AnyObject.
The difference is that in the second solution, the object can only be
converted back to the original number type Int32, but not to
Int or any other integer type.

For the other problems, see

  • Issue with UnsafePointer<Uint8> in SQLite project in Swift
  • Error in for loop CGFloat

Problem with SQLite.swift after migration to Swift 5

Till SQLite.swift doesn't release any update with the fix you could try modify manually the SQLite/Foundation.swift for fromDatatypeValue(_ dataValue: Blob) function and the computed property datatypeValue in this way:

public static func fromDatatypeValue(_ dataValue: Blob) -> Data {
return Data(dataValue.bytes)
}

public var datatypeValue: Blob {
return withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Blob in
return Blob(bytes: pointer.baseAddress!, length: count)
}
}

Swift 3: convert a null-terminated UnsafePointer UInt8 to a string

In Swift 3, String has two initializers

public init(cString: UnsafePointer<CChar>)
public init(cString: UnsafePointer<UInt8>)

therefore it can be created from (null-terminated) sequences of both signed and unsigned characters. So

let s = String(cString: yourCharPointer)

should just work.


String has another initializer

public init?(validatingUTF8 cString: UnsafePointer<CChar>)

which fails on ill-formed UTF-8 sequences instead of replacing them
by the replacement characters. This init method has no counterpart
taking unsigned characters.

Taking the existing implementations in CString.swift as examples, it is not too difficult to add this as an extension:

extension String {
public init?(validatingUTF8 cString: UnsafePointer<UInt8>) {
guard let (s, _) = String.decodeCString(cString, as: UTF8.self,
repairingInvalidCodeUnits: false) else {
return nil
}
self = s
}
}

and then

if let s = String(validatingUTF8: yourCharPointer) {
print(s)
} else {
print("invalid UTF-8")
}

also works with (null-terminated) sequences of both signed and unsigned characters.

Create UnsafeMutablePointer UInt8 in Swift 3

(DES is not secure and should not be used in new work; it has been superceed by AES)

Example fragment:

let cryptLength = size_t(data.count + kCCBlockSizeDES)
var cryptData = Data(repeating:0, count:cryptLength)
var numBytesEncrypted :size_t = 0

let keyLength = size_t(kCCKeySizeDES)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding)

let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
ivData.withUnsafeBytes {ivBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(operation),
algoritm,
options,
keyBytes, keyLength,
ivBytes,
dataBytes, data.count,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}
}
}

Example from sunsetted documentation section:

AES encryption in CBC mode with a random IV (Swift 3+)

The iv is prefixed to the encrypted data

aesCBC128Encrypt will create a random IV and prefixed to the encrypted code.

aesCBC128Decrypt will use the prefixed IV during decryption.

Inputs are the data and key are Data objects. If an encoded form such as Base64 if required convert to and/or from in the calling method.

The key should be exactly 128-bits (16-bytes), 192-bits (24-bytes) or 256-bits (32-bytes) in length. If another key size is used an error will be thrown.

PKCS#7 padding is set by default.

This example requires Common Crypto

It is necessary to have a bridging header to the project:

#import <CommonCrypto/CommonCrypto.h>
Add the Security.framework to the project.

This is example, not production code.

enum AESError: Error {
case KeyError((String, Int))
case IVError((String, Int))
case CryptorError((String, Int))
}

// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}

let ivSize = kCCBlockSizeAES128;
let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength)

let status = cryptData.withUnsafeMutableBytes {ivBytes in
SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
}
if (status != 0) {
throw AESError.IVError(("IV generation failed", Int(status)))
}

var numBytesEncrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)

let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
options,
keyBytes, keyLength,
cryptBytes,
dataBytes, data.count,
cryptBytes+kCCBlockSizeAES128, cryptLength,
&numBytesEncrypted)
}
}
}

if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.count = numBytesEncrypted + ivSize
}
else {
throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
}

return cryptData;
}

// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
let keyLength = keyData.count
let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
if (validKeyLengths.contains(keyLength) == false) {
throw AESError.KeyError(("Invalid key length", keyLength))
}

let ivSize = kCCBlockSizeAES128;
let clearLength = size_t(data.count - ivSize)
var clearData = Data(count:clearLength)

var numBytesDecrypted :size_t = 0
let options = CCOptions(kCCOptionPKCS7Padding)

let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
options,
keyBytes, keyLength,
dataBytes,
dataBytes+kCCBlockSizeAES128, clearLength,
cryptBytes, clearLength,
&numBytesDecrypted)
}
}
}

if UInt32(cryptStatus) == UInt32(kCCSuccess) {
clearData.count = numBytesDecrypted
}
else {
throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
}

return clearData;
}

Example usage:

let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData: \(clearData as NSData)")
print("keyData: \(keyData as NSData)")

var cryptData :Data?
do {
cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
print("cryptData: \(cryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCEncrypt: \(status)")
}

let decryptData :Data?
do {
let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
print("Error aesCBCDecrypt: \(status)")
}

Example Output:

clearData:   <636c6561 72446174 61303132 33343536>
keyData: <6b657944 61746138 39303132 33343536>
cryptData: <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>

Notes:

One typical problem with CBC mode example code is that it leaves the creation and sharing of the random IV to the user. This example includes generation of the IV, prefixed the encrypted data and uses the prefixed IV during decryption. This frees the casual user from the details that are necessary for CBC mode.

For security the encrypted data also should have authentication, this example code does not provide that in order to be small and allow better interoperability for other platforms.

Also missing is key derivation of the key from a password, it is suggested that PBKDF2 be used is text passwords are used as keying material.

For robust production ready multi-platform encryption code see RNCryptor.

How to use SCNetworkReachability in Swift

(This answer was extended repeatedly due to changes in the Swift language, which made it a bit confusing. I have now rewritten it and removed everything which refers to Swift 1.x. The older code can
be found in the edit history if somebody needs it.)

This is how you would do it in Swift 2.0 (Xcode 7):

import SystemConfiguration

func connectedToNetwork() -> Bool {

var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)

guard let defaultRouteReachability = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else {
return false
}

var flags : SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}

let isReachable = flags.contains(.Reachable)
let needsConnection = flags.contains(.ConnectionRequired)

return (isReachable && !needsConnection)
}

Explanations:

  • As of Swift 1.2 (Xcode 6.3), imported C structs have a default initializer in Swift, which initializes all of the struct's fields to zero, so the socket address structure can be initialized with

    var zeroAddress = sockaddr_in()
  • sizeofValue() gives the size of this structure, this has
    to be converted to UInt8 for sin_len:

    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
  • AF_INET is an Int32, this has to be converted to the correct type for sin_family:

    zeroAddress.sin_family = sa_family_t(AF_INET)
  • withUnsafePointer(&zeroAddress) { ... } passes the address of the
    structure to the closure where it is used as argument for
    SCNetworkReachabilityCreateWithAddress(). The UnsafePointer($0)
    conversion is needed because that function expects a pointer to
    sockaddr, not sockaddr_in.

  • The value returned from withUnsafePointer() is the return value
    from SCNetworkReachabilityCreateWithAddress() and that has the
    type SCNetworkReachability?, i.e. it is an optional.
    The guard let statement (a new feature in Swift 2.0) assigns the unwrapped value to the defaultRouteReachability variable if it is
    not nil. Otherwise the else block is executed and the function
    returns.

  • As of Swift 2, SCNetworkReachabilityCreateWithAddress() returns
    a managed object. You don't have to release it explicitly.
  • As of Swift 2, SCNetworkReachabilityFlags conforms to
    OptionSetType which has a set-like interface. You create an
    empty flags variable with

    var flags : SCNetworkReachabilityFlags = []

    and check for flags with

    let isReachable = flags.contains(.Reachable)
    let needsConnection = flags.contains(.ConnectionRequired)
  • The second parameter of SCNetworkReachabilityGetFlags has the type
    UnsafeMutablePointer<SCNetworkReachabilityFlags>, which means that you have to
    pass the address of the flags variable.

Note also that registering a notifier callback is possible as of
Swift 2, compare Working with C APIs from Swift and Swift 2 - UnsafeMutablePointer<Void> to object.


Update for Swift 3/4:

Unsafe pointers cannot be simply be converted to a pointer of a
different type anymore (see - SE-0107 UnsafeRawPointer API). Here the updated code:

import SystemConfiguration

func connectedToNetwork() -> Bool {

var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)

guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
return false
}

var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}

let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)

return (isReachable && !needsConnection)
}

unexpectedly found nil while unwrapping an Optional value while reading from DS with fromCString

Another possible solution is this:

let unsafepointer=UnsafePointer<CChar>(sqlite3_column_text(statement, 2));
var sText = "unsafe text pointer is nil !";
if unsafepointer != nil{
if let text = String.fromCString(unsafepointer) as String?{
sText = text;
}
}

Creating custom sqlite functions in Swift alone

SQLite.swift provides a type-safe Swift interface for creating custom SQL functions (disclaimer: I wrote and maintain SQLite.swift). The current version bridges to Objective-C internally, though this is an implementation detail you can ignore. A future version will likely use Swift 2's function pointer API. And while you can use C function pointers in Swift 1.x with some @objc_block and unsafeBitCast, it's quite a bit worse to read and maintain.

The most basic way to create a cos function:

import SQLite
import Darwin

// opens a database connection
let db = Database()

// defines a "cos" function on the connection
db.create(function: "cos", argc: 1, deterministic: true) { args in
if let x = args[0] as? Double {
return Darwin.cos(x)
}
return nil
}

println(db.scalar("SELECT cos(1.0)"))
// Optional(0.54030230586813977)

A more complex, safer example wherein SQLite.swift generates a type-safe interface to your database given a contract:

import SQLite
import Darwin

// opens a database connection
let db = Database()

// defines a "cos" function on the connection
let cos: Expression<Double> -> Expression<Double> = (
db.create(function: "cos", deterministic: true, Darwin.cos)
)

// builds a SQL expression for the column, "x"
let x = Expression<Double>("x")

// creates a query reference for the table, "table"
let table = db["table"]

// creates the table
db.create(table: table) { t in
t.column(x)
}
// CREATE TABLE "table" ("x" REAL)

// inserts a row where "x" is 1.0
table.insert(x <- 1.0)
// INSERT INTO "table" ("x") VALUES (1.0)

// executes the query
for row in db.select(cos(x)) {
println(row[cos(x)])
}
// SELECT "cos"("x") FROM "table"


Related Topics



Leave a reply



Submit