I'm trying to decode some binary chunks into various fixed width integers in iOS. The format of the abridged data features 5 UInt32s, followed by n amount of Int16s.
Each chunk I receive features 1 initial byte of UInt8 stating the size of that payload, followed by 244 bytes of actual data. My approach has been to discard this initial byte and append the remaining data to a data buffer using the following code:
let payload = data.advanced(by: 1)
payloadBuffer.append(payload)
After receiving the expected total amount of bytes (determined by payloadBuffer.count), I perform a crc32 check to ensure data integrity, which passes.
All good so far!
However I've noticed that if I want to slice the payloadBuffer and remove the initial 20 bytes to focus solely on the Int16's using a similar approach to above the index is always out by 2 bytes.
So when I use the following I seem to lose the initial Int16 value:
let slicedBuffer = payload.advanced(by: 20)
However if I use:
let slicedBuffer = payload.advanced(by: 18)
I am correctly getting the initial Int16 value, even though you would assume this is the last two bytes of the previous UInt32.
I'm using the following code to decode the slicedBuffer (usually with a byte offset):
Int16(littleEndian: trimmedBuffer.withUnsafeBytes({ $0.load(as: Int16.self) }))
I've tried using subscripting instead of .advanced(by:), as well as .subData(in:), but still getting the same result. I've also tried different methods to decode the Int16s, such as some of the following:
let test = payloadBuffer.withUnsafeBytes { bytes -> Int16 in
let int: Int16 = bytes.loadFixedWidthInteger(fromByteOffset: 20)
return int
}
extension UnsafeRawBufferPointer {
func loadFixedWidthInteger<T: FixedWidthInteger>(fromByteOffset offset: Int) -> T {
var value: T = 0
withUnsafeMutableBytes(of: &value) { valuePtr in
valuePtr.copyBytes(from: UnsafeRawBufferPointer(start: self.baseAddress!.advanced(by: offset),
count: MemoryLayout<T>.size))
}
return value
}
}
or simply...
Int16(bytes[21]) << 8 | Int16(bytes[20])
I believe this has something to do with the fact that the bytes are unaligned in memory? I've read through many forum posts related to unaligned loads (e.g. 1, 2), but none of the suggested solutions seem to resolve the issue:
Stack Overflow - Creating an aligned array of bytes
For the life of me though I cannot work out what is causing this quirk? If anyone has any suggestions I'd be very grateful!