This is my loop code:
let entyLimitLength = 256 // word enty must smaller than 256
let sizeOfWordDataOffset = 4 // 4 bytes or 8 byte if 64 bit
let sizeOfWordDataSize = 4 //4 bytes or 8 byte if 64 bit
var entyLocation = 0
var entyLength = 0
var searchRange:NSRange
var subDataEnty:NSData
var wordDataOffset:UInt32 = 0
var wordDataSize:UInt32 = 0
var rslt = [(String,NSData)]()
while entyLocation < idxData.length{
searchRange = idxData.rangeOfData(nulTerminateCharacter, options: searchOption, range: NSMakeRange(entyLocation, min(entyLimitLength,(idxData.length - entyLocation))))
if searchRange.length == 0 {
break // not match
}
entyLength = searchRange.location - entyLocation
// this is what data sequene we need
subDataEnty = idxData.subdataWithRange(NSMakeRange(entyLocation, entyLength))
//point to offset number 's data sequene
entyLocation = searchRange.location + searchRange.length
//use pointer to get result ##
idxData.getBytes(&wordDataOffset, range: NSMakeRange(entyLocation,sizeOfWordDataOffset))
//swap Big endian to Litter endian (host)
wordDataOffset = CFSwapInt32BigToHost(wordDataOffset)
//point to word data size's data sequene
entyLocation = entyLocation + sizeOfWordDataOffset
//the same for word data size
idxData.getBytes(&wordDataSize, range: NSMakeRange(entyLocation,sizeOfWordDataSize))
wordDataSize = CFSwapInt32BigToHost(wordDataSize)
//point to next data sequene
entyLocation = entyLocation + sizeOfWordDataSize
rslt = rslt + [(NSString(data: subDataEnty, encoding: NSUTF8StringEncoding) as! String , dictData.subdataWithRange(NSMakeRange(Int(wordDataOffset), Int(wordDataSize))))]
}
return rslt
It take NSData form file and change it in to [(String,NSData)] array
This while loop run above 200000 times. In Xcode Simulation it take too much time.I dont think it take too long time as it is . Is there some reason make it slow down ?
and Please dont vote down a newbie question guys.
Related
In my project, I communicate with a bluetooth device, the bluetooth device must send me a timestamp second, I received in byte:
[2,6,239]
When I convert converted to a string:
let payloadString = payload.map {
String(format: "%02x", $0)
}
Output:
["02", "06","ef"]
When I converted from the website 0206ef = 132847 seconds
How can I directly convert my aray [2,6,239] in second (= 132847 seconds)?
And if it's complicated then translate my array ["02", "06,"ef"] in second (= 132847 seconds)
The payload contains the bytes of the binary representation of the value.
You convert it back to the value by shifting each byte into its corresponding position:
let payload: [UInt8] = [2, 6, 239]
let value = Int(payload[0]) << 16 + Int(payload[1]) << 8 + Int(payload[2])
print(value) // 132847
The important point is to convert the bytes to integers before shifting, otherwise an overflow error would occur. Alternatively,
with multiplication:
let value = (Int(payload[0]) * 256 + Int(payload[1])) * 256 + Int(payload[2])
or
let value = payload.reduce(0) { $0 * 256 + Int($1) }
The last approach works with an arbitrary number of bytes – as long as
the result fits into an Int. For 4...8 bytes you better choose UInt64
to avoid overflow errors:
let value = payload.reduce(0) { $0 * 256 + UInt64($1) }
payloadString string can be reduced to hexStr and then converted to decimal
var payload = [2,6,239];
let payloadString = payload.map {
String(format: "%02x", $0)
}
//let hexStr = payloadString.reduce(""){$0 + $1}
let hexStr = payloadString.joined()
if let value = UInt64(hexStr, radix: 16) {
print(value)//132847
}
I need 16383 to be converted to 7F7F but I can only get this to be converted to 3fff or 77377.
I can convert 8192 to hexadecimal string 4000 which is essentially the same thing.
If I use let firstHexa = String(format:"%02X", a) It stops at 3fff hexadecimal for the first number and and 2000 hexadecimal for the second number. here is my code
public func intToHexString(_ int: Int16) -> String {
var encodedHexa: String = ""
if int >= -8192 && int <= 8191 {
let int16 = int + 8192
//convert to two unsigned Int8 bytes
let a = UInt8(int16 >> 8 & 0x00ff)
let b = UInt8(int16 & 0x00ff)
//convert the 2 bytes to hexadecimals
let first1Hexa = String(a, radix: 8 )
let second2Hexa = String(b, radix: 8)
let firstHexa = String(format:"%02X", a)
let secondHexa = String(format:"%02X", b)
//combine the 2 hexas into 1 string with 4 characters...adding 0 to the beggining if only 1 character.
if firstHexa.count == 1 {
let appendedFHexa = "0" + firstHexa
encodedHexa = appendedFHexa + secondHexa
} else if secondHexa.count == 1 {
let appendedSHexa = "0" + secondHexa
encodedHexa = firstHexa + appendedSHexa
} else {
encodedHexa = firstHexa + secondHexa
}
}
return encodedHexa
}
Please help ma'ams and sirs! Thanks.
From your test cases, it seems like your values are 7 bits per byte.
You want 8192 to convert to 4000.
You want 16383 to convert to 7F7F.
Note that:
(0x7f << 7) + 0x7f == 16383
Given that:
let a = UInt8((int16 >> 7) & 0x7f)
let b = UInt8(int16 & 0x7f)
let result = String(format: "%02X%02X", a , b)
This gives:
"4000" for 8128
"7F7F" for 16383
To reverse the process:
let str = "7F7F"
let value = Int(str, radix: 16)!
let result = ((value >> 8) & 0x7f) << 7 + (value & 0x7f)
print(result) // 16383
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
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))
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.
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 ?
I am writing code to read and write file using a rigidly defined binary format. I have a mixture of Int16 and Int32 values, which are defined as a 240 byte structure. How do I concatenate these values into this single structure?
here is an example, you can custom your own init method, use loop if there two many repeated length
public struct HistoryRecord {
public let sequence: UInt8
let impFlag: UInt8
let mode: UInt8
let power: UInt16
let utc: UInt32
let weight: UInt16
let impedance: UInt16
private let sequenceLength = 1
private let modeLength = 1
private let powerLength = 2
private let utcLength = 4
private let weightLength = 2
private let impedanceLength = 2
public init() {
sequence = 0
impFlag = 0
mode = 0
power = 0
utc = 0
weight = 0
impedance = 0
}
public init?(_ data: NSData) {
let needLength = sequenceLength + modeLength + powerLength + utcLength + weightLength + impedanceLength
guard data.length == needLength else {
return nil
}
var bufferUInt8: UInt8
var bufferUInt16: UInt16
var bufferUInt32: UInt32
bufferUInt8 = 0
data.getBytes(&bufferUInt8, range: NSMakeRange(0, sequenceLength))
sequence = bufferUInt8
bufferUInt8 = 0
data.getBytes(&bufferUInt8, range: NSMakeRange(sequenceLength, modeLength))
impFlag = (bufferUInt8 >> 4) & 0x00ff
mode = bufferUInt8 & 0x00ff
bufferUInt16 = 0
data.getBytes(&bufferUInt16, range: NSMakeRange(sequenceLength + modeLength, powerLength))
power = bufferUInt16.bigEndian
bufferUInt32 = 0
data.getBytes(&bufferUInt32, range: NSMakeRange(sequenceLength + modeLength + powerLength, utcLength))
utc = bufferUInt32.bigEndian
bufferUInt16 = 0
data.getBytes(&bufferUInt16, range: NSMakeRange(sequenceLength + modeLength + powerLength + utcLength, weightLength))
weight = bufferUInt16.bigEndian
bufferUInt16 = 0
data.getBytes(&bufferUInt16, range: NSMakeRange(sequenceLength + modeLength + powerLength + utcLength + weightLength, impedanceLength))
impedance = bufferUInt16.bigEndian
I am trying to convert a 6 byte hex of type NSData i got via bluetooth connection to appropriate integer values. I know this is of type Big Endian and i need to covnert to little Endian. However, every time i try to convert it, i can extract the right data, but the results look wrong, see playground code below:
var newdata = NSData(bytes: [0x26, 0x01, 0x45, 0x01, 0x04, 0x5e, ] as [UInt8], length:6)
//var timeData = newdata.subdataWithRange(NSMakeRange(4,2))
//var heelData = newdata.subdataWithRange(NSMakeRange(2,2))
//var frontData = newdata.subdataWithRange(NSMakeRange(0,2))
var timeData:UInt16 = 0
var heelData:UInt16 = 0
var frontData:UInt16 = 0
//var timeData = data.subdataWithRange(NSMakeRange(4,2))
var timeIn: NSNumber = NSNumber(unsignedShort: 0)
newdata.getBytes(&timeIn, range: NSRange(location: 4,length: 2))
timeData = CFSwapInt16BigToHost(timeIn.unsignedShortValue)
//24068
var heelIn: NSNumber = NSNumber(unsignedShort: 0)
newdata.getBytes(&heelIn, range: NSRange(location: 2, length: 2))
heelData = CFSwapInt16BigToHost(heelIn.unsignedShortValue)
//325
var frontIn: NSNumber = NSNumber(unsignedShort: 0)
newdata.getBytes(&frontIn, range: NSRange(location: 0, length: 2))
frontData = CFSwapInt16BigToHost(frontIn.unsignedShortValue)
//294
NSNumber is a Foundation class and in particular a value type,
and timeIn is a pointer to a number instance.
You are extracting the bytes into that pointer, which is not what you want
and can cause all kinds of undefined behavior or crashes.
What you should do is to extract the bytes into an UInt16 variable:
var timeData:UInt16 = 0
newdata.getBytes(&timeData, range: NSRange(location: 4, length: 2))
timeData = CFSwapInt16BigToHost(timeData)
// Result: 1118 = 0x045E
An alternative to the last conversion is
/// Creates an integer from its big-endian representation, changing the
/// byte order if necessary.
timeData = UInt16(bigEndian: timeData)