hotpaw2
hotpaw2

Reputation: 70673

How to get bytes out of an UnsafeMutableRawPointer?

How does one access bytes (or Int16's, floats, etc.) out of memory pointed to by an UnsafeMutableRawPointer (new in Swift 3) handed to a Swift function by a C API (Core Audio, etc.)

Upvotes: 29

Views: 22204

Answers (4)

Mike Lee
Mike Lee

Reputation: 2639

Here's a Swift 4 example of converting a literal UInt8 array to an UnsafeMutableRawPointer and back to an UInt32 array

static func unsafePointerTest() {
    //let a : [UInt8] = [0,0,0,4,0,0,0,8,0,0,0,12]
    let a : [UInt8] = [0x04, 0x00, 0x00, 0x00,
                       0x08, 0x00, 0x00, 0x00,
                       0x0C, 0x00, 0x00, 0x00] //little endian
    //0xFF, 0xF0, 0xF0, 0x12]  //317780223 = 12F0F0FF
    let b:UnsafeMutableRawPointer = UnsafeMutableRawPointer(mutating:a)
    let bTypedPtr = b.bindMemory(to: UInt32.self, capacity: a.count/4)
    let UInt32Buffer = UnsafeBufferPointer(start: bTypedPtr, count: a.count/4)
    let output = Array(UInt32Buffer)
    print(output)
}

Upvotes: 4

Sverrisson
Sverrisson

Reputation: 18157

Create Data object.

init(bytesNoCopy bytes: UnsafeMutableRawPointer, count: Int, deallocator: Data.Deallocator)

One important way missing from the other answers here is initialising a Data object with UnsafeMutableRawPointer. The data object can then be used for other calculations.

public func base64(quality: Int32 = 67) -> String? {
    var size: Int32 = 0
    if let image = gdImageJpegPtr(internalImage, &size, quality) {
        // gdImageJpegPtr returns an UnsafeMutableRawPointer that is converted to a Data object
        let d = Data(bytesNoCopy: image, count: Int(size), deallocator: .none)
        return d.base64EncodedString()
    }
    return nil
}

Upvotes: 3

Ankit Thakur
Ankit Thakur

Reputation: 4749

Here are the api documentation of Unsafe[Mutable]RawPointer to T/Unsafe[MutablePointer] conversion:

/// Binds the allocated memory to type `T` and returns an
/// `UnsafePointer<T>` to the bound memory at `self`.
///
/// - Precondition: The memory is uninitialized.
/// - Postcondition: The memory is bound to 'T' starting at `self` continuing
///   through `self` + `count` * `MemoryLayout<T>.stride`
/// - Warning: Binding memory to a type is potentially undefined if the
///   memory is ever accessed as an unrelated type.
public func bindMemory<T>(to type: T.Type, capacity count: Int) -> UnsafePointer<T>

/// Converts from an `UnsafeRawPointer` to UnsafePointer<T> given that
/// the region of memory starting at `self` is already bound to type `T`.
///
/// - Precondition: The memory is bound to 'T' starting at `self` for some
///   unspecified capacity.
///
/// - Warning: Accessing memory via the returned pointer is undefined if the
///   if the memory has not been bound to `T`.
public func assumingMemoryBound<T>(to: T.Type) -> UnsafePointer<T>

/// Reads raw bytes from memory at `self + offset` and constructs a
/// value of type `T`.
///
/// - Precondition: The underlying pointer plus `offset` is properly
///   aligned for accessing `T`.
///
/// - Precondition: The memory is initialized to a value of some type, `U`,
///   such that `T` is layout compatible with `U`.
public func load<T>(fromByteOffset offset: Int = default, as type: T.Type) -> T

and then from Unsafe[MutablePointer]<T> toT can be converted with pointee and move apis

/// Accesses the `Pointee` instance referenced by `self`.
///
/// - Precondition: the pointee has been initialized with an instance of
///   type `Pointee`.
public var pointee: Pointee { get }

/// Retrieves the `pointee`, returning the referenced memory to an
/// uninitialized state.
///
/// Equivalent to `{ defer { deinitialize() }; return pointee }()`, but
/// more efficient.
///
/// - Precondition: The pointee is initialized.
///
/// - Postcondition: The memory is uninitialized.
public func move() -> Pointee

Upvotes: 2

Martin R
Martin R

Reputation: 539685

load<T> reads raw bytes from memory and constructs a value of type T:

let ptr = ... // Unsafe[Mutable]RawPointer
let i16 = ptr.load(as: UInt16.self)

optionally at a byte offset:

let i16 = ptr.load(fromByteOffset: 4, as: UInt16.self)

There is also assumingMemoryBound() which converts from a Unsafe[Mutable]RawPointer to a Unsafe[Mutable]Pointer<T>, assuming that the pointed-to memory contains a value of type T:

let i16 = ptr.assumingMemoryBound(to: UInt16.self).pointee

For an array of values you can create a "buffer pointer":

let i16bufptr = UnsafeBufferPointer(start: ptr.assumingMemoryBound(to: UInt16.self), count: count)

A buffer pointer might already be sufficient for your purpose, it is subscriptable and can be enumerated similarly to an array. If necessary, create an array from the buffer pointer:

let i16array = Array(i16bufptr)

As @Hamish said, more information and details can be found at

Upvotes: 51

Related Questions