I'm working with binary data which has a string encoded in the middle. What I'm trying to do is extract this string so that I can both "set" and "get" it. I've come up with a methodology which seems a little funky (actually 3 options). I've included a playground code which you can look at.
I'm wondering if there is a "better" way to work with this data than what I've come up. Better means more efficient or clearer code-wise.
To read the data I do the following -
var rawData
by converting the NSMutableData
to UnsafeMutablePoitner<UInt8>
var ptr : UnsafeMutablePointer<UInt8>
from rawData.mutableBytes
bytes
of type UnsafeMutableBufferPointer<UInt8>
from a combo of the 1st two variablesbytes[19]
- bytes[26]
Then to set the variable I have 3 methods but the one I think I would use is
1. Make a new string of 8 string
2. Create [UInt8]
array of the characters of the string
3. Loop through each byte in the new array and set the value of the byte in the bytes
array to the value in question
I'm assuming there is some way where I can be working directly with the "parent" byte array as opposed to making a sub-array to work with. Playground code is below. I'm looking for a cleaner way to do this and perhaps there is not one.
Thanks
import Cocoa
//import AppKit
///This is the raw data
var testBytes : [UInt8] = [0x14, 0x00, 0xAB, 0x45, 0x49, 0x1F, 0xEF, 0x15, 0xA8, 0x89, 0x78, 0x0F, 0x09, 0xA9, 0x07, 0xB0, 0x01, 0x20, 0x01, 0x4E, 0x38, 0x32, 0x35, 0x56, 0x20, 0x20, 0x20, 0x00]
///Convert into msgData
var msgData = NSMutableData(bytes: testBytes, length: testBytes.count)
// Store raw data into a byte array for messing with
var rawData: NSMutableData = NSMutableData(data: msgData)
var ptr: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>(rawData.mutableBytes)
var bytes : UnsafeMutableBufferPointer<UInt8> = UnsafeMutableBufferPointer<UInt8>(start: ptr, count: rawData.length)
// Extract Callsign from the data stream
var callsignArray : [UInt8] = [bytes[19], bytes[20], bytes[21], bytes[22], bytes[23], bytes[24], bytes[25], bytes[26]]
var callsignString = NSString(bytes: callsignArray, length: callsignArray.count, encoding: NSUTF8StringEncoding)
let callsignString0 = callsignString!
println(callsignArray)
println("1. -- Initial Callsign [\(callsignString0)]")
//OPTION #1
// Edit Callsgin Array Directly (sketchy)
// And manually copy the bytes back into the base array
callsignArray[0] = 97
callsignArray[1] = 98
callsignArray[2] = 99
callsignArray[3] = 100
println(callsignArray)
// Write the new "bytes" back into the main array - there must be a better way
for (var i = 0; i <= 7; i++) {
bytes[19+i] = callsignArray[i]
}
let callsign1 = NSString(bytes: callsignArray, length: callsignArray.count, encoding: NSUTF8StringEncoding)!
println("2. -- Modification of Bytes [\(callsign1)]")
//Option 3 - Go from String to Bytes
let callsign3 = "AABCDEF "
var buf = [UInt8](callsign3.utf8)
for (var i = 0; i <= 7; i++) {
bytes[19+i] = buf[i]
}
println(rawData)
callsignArray = [bytes[19], bytes[20], bytes[21], bytes[22], bytes[23], bytes[24], bytes[25], bytes[26]]
callsignString = NSString(bytes: callsignArray, length: callsignArray.count, encoding: NSUTF8StringEncoding)
NSMutableData
has methods to extract and replace sub-ranges:
// Get:
let subData = msgData.subdataWithRange(NSMakeRange(19, 8))
let string = NSString(data: subData, encoding: NSUTF8StringEncoding)
// Set:
let newString = "AABCDEF "
let newData = newString.dataUsingEncoding(NSUTF8StringEncoding)!
msgData.replaceBytesInRange(NSMakeRange(19, 8), withBytes: newData.bytes, length: newData.length)
You can also operate on the [UInt8]
array directly:
// Get:
let string = testBytes.withUnsafeBufferPointer {
NSString(bytes: UnsafePointer($0.baseAddress + 19), length: 8, encoding: NSUTF8StringEncoding)
}
// Set:
testBytes.replaceRange(19 ... 26, with: Array(newString.utf8))