Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract float from byte data

I need to extract some listmode bigEndian Float data from a binary file format. I was originally using the following method and it worked perfectly, but I am having trouble converting this over to Swift 3...

Original: (example of 20 rows with 15 columns of data that start after 300 bytes of header)

let fileData: NSData = NSData(contentsOfFile: fileInfo.path)!
let ptr = UnsafePointer<UInt8>(fileData.bytes)
let byteOffset = 300
for i in 0..<20 {

    let byteOffset2 = byteOffset + (i * 15 * 4)

    for p in 0..<15 {
        let bits = UnsafePointer<Float._BitsType>(ptr + byteOffset2)[p].bigEndian
        let f = Float._fromBitPattern(bits)
        eventData[p] = f
    }
} 

New: (after the automated Xcode conversion and some attempted tweaking to remove errors in Xcode)

let fileData: Data = try! Data(contentsOf: URL(fileURLWithPath: fileInfo.path))
let ptr = (fileData as NSData).bytes.bindMemory(to: UInt32.self, capacity: fileData.count)
let byteOffset = 300

for i in 0..<20 {

    let byteOffset2 = byteOffset + (i * 15 * 4)

    for p in 0..<15 {
        let bits = UnsafePointer<UInt32>(ptr + byteOffset2)[p].bigEndian 
        let f = Float(bitPattern: bits)
        eventData[p] = f
    }
}

The values generated from the new method are now incorrect... I have been fiddling for quite a while now and I am stumped - any advice would be much appreciated. I found my original method in this question/answer: Swift: extract float from byte data but it seems that Float._BitsType doesn't work in Swift 3. Any advice will be much appreciated...

like image 315
Immunomonkey Avatar asked Mar 11 '26 19:03

Immunomonkey


1 Answers

The problem (if I guess correctly) is that ptr in your attempted Swift 3 code is a pointer to UInt32 and not to UInt8 as in the Swift 2 version. Therefore ptr + byteOffset2 advances the pointer by 4 * byteOffset2 bytes, and that must be considered when computing the offsets.

Generally you can simplify the access to Data like this:

data.withUnsafeBytes { (ptr: UnsafePointer<UInt32>) in

    let uint32Offset = 300/MemoryLayout<UInt32>.stride // 300/4 = 75

    for i in 0 ..< 20 {
        for p in 0 ..< 15 {

            let offset = uint32Offset + i * 15 + p
            let u32Value = UInt32(bigEndian: ptr[offset])
            let floatValue = Float(bitPattern: u32Value)
            // ...
        }
    }
}
like image 195
Martin R Avatar answered Mar 14 '26 09:03

Martin R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!