bleeckerj
bleeckerj

Reputation: 564

Two Ways To Get 4 Bytes of (Swift3) Data Into a UInt32

So, I have a stream of well-formed data coming from some hardware. The stream consists of a bunch of chunks of 8-bit data, some of which are meant to form into 32-bit integers. That's all good. The data moves along and now I want to parcel the sequence up.

The data is actually a block of contiguous bytes, with segments of it mapped to useful data. So, for example, the first byte is a confirmation code, the following four bytes represent a UInt32 of some application-specific meaning, followed by two bytes representing a UInt16, and so on for a couple dozen bytes.

I found two different ways to do that, both of which seem a bit..overwrought. It may just what happens when you get close to the metal.

But — are these two code idioms generally what one should expect to do? Or am I missing something more compact?

  // data : Data exists before this code, and has what we're transforming into UInt32

  // One Way to get 4  bytes from Data into a UInt32
  var y : [UInt8] = [UInt8](repeating:UInt8(0x0), count: 4)
  data.copyBytes(to: &y, from: Range(uncheckedBounds: (2,6)))
  let u32result = UnsafePointer(y).withMemoryRebound(to: UInt32.self, capacity: 1, {
       $0.pointee
  })
  // u32result contains the 4 bytes from data

  // Another Way to get 4 bytes from Data into a UInt32 via NSData
  var result : UInt32 = 0
  let resultAsNSData : NSData = data.subdata(in: Range(uncheckedBounds: (2,6))) as NSData
  resultAsNSData.getBytes(&result, range: NSRange(location: 0, length: 4))
  // result contains the 4 bytes from data

Upvotes: 4

Views: 8068

Answers (3)

Oleksii Radetskyi
Oleksii Radetskyi

Reputation: 227

let a = [ 0x00, 0x00, 0x00, 0x0e ]
let b = a[0] << 24 + a[1] << 16 + a[2] << 8 + a[3]
print(b) // will print 14. 

Should I describe this operation ?

Upvotes: -1

bleeckerj
bleeckerj

Reputation: 564

I found two other ways of doing this which is leading me to believe that there are plenty of ways to do it, which is good, I suppose. Two additional ways are described in some fashion over on Ray Wenderlich

This code dropped into your Xcode playground will reveal these two other idioms.

do {
let count = 1 // number of UInt32s
let stride = MemoryLayout<UInt32>.stride
let alignment = MemoryLayout<UInt32>.alignment
let byteCount = count * stride

var bytes : [UInt8] = [0x0D, 0x0C, 0x0B, 0x0A] // little-endian LSB -> MSB
var data : Data = Data.init(bytes: bytes) // In my situtation, I actually start with an instance of Data, so the [UInt8] above is a conceit.

print("---------------- 1 ------------------")

let placeholder = UnsafeMutableRawPointer.allocate(bytes: byteCount, alignedTo:alignment)

withUnsafeBytes(of: &data, { (bytes) in
    for (index, byte) in data.enumerated() {
        print("byte[\(index)]->\(String(format: "0x%02x",byte)) data[\(index)]->\(String(format: "0x%02x", data[index])) addr: \(bytes.baseAddress!+index)")

        placeholder.storeBytes(of: byte, toByteOffset: index, as: UInt8.self)

    }
})
let typedPointer1 = placeholder.bindMemory(to: UInt32.self, capacity: count)
print("u32: \(String(format: "0x%08x", typedPointer1.pointee))")



print("---------------- 2 ------------------")

for (index, byte) in bytes.enumerated() {
    placeholder.storeBytes(of: byte, toByteOffset: index, as: UInt8.self)
   // print("byte \(index): \(byte)")
    print("byte[\(index)]->\(String(format: "0x%02x",byte))")

}
let typedPointer = placeholder.bindMemory(to: UInt32.self, capacity: count)
print(typedPointer.pointee)
let result : UInt32 = typedPointer.pointee
print("u32: \(String(format: "0x%08x", typedPointer.pointee))")
}

With output:

---------------- 1 ------------------
byte[0]->0x0d data[0]->0x0d addr: 0x00007fff57243f68
byte[1]->0x0c data[1]->0x0c addr: 0x00007fff57243f69
byte[2]->0x0b data[2]->0x0b addr: 0x00007fff57243f6a
byte[3]->0x0a data[3]->0x0a addr: 0x00007fff57243f6b
u32: 0x0a0b0c0d
---------------- 2 ------------------
byte[0]->0x0d
byte[1]->0x0c
byte[2]->0x0b
byte[3]->0x0a
168496141
u32: 0x0a0b0c0d

Here's a Gist.

Upvotes: 2

ERbittuu
ERbittuu

Reputation: 978

Creating UInt32 array from well-formed data object.

Swift 3

// Create sample data
let data = "foo".data(using: .utf8)!

// Using pointers style constructor
let array = data.withUnsafeBytes {
    [UInt32](UnsafeBufferPointer(start: $0, count: data.count))
}
    

Swift 2

// Create sample data
let data = "foo".dataUsingEncoding(NSUTF8StringEncoding)!
        
// Using pointers style constructor
let array = Array(UnsafeBufferPointer(start: UnsafePointer<UInt32>(data.bytes), count: data.length))

Upvotes: 2

Related Questions