[英]How to byte reverse NSData output in Swift the littleEndian way?
我有來自 NSData 的輸出:<00000100 84000c00 071490fe 4dfbd7e9>
那么我怎么能在 Swift 中對它進行字節反轉並得到這個輸出:<00000001 0084000c 1407fe90 fb4de9d7>?
這應該可以交換數據中的每對相鄰字節。 這個想法是將字節解釋為UInt16
整數數組並使用內置的byteSwapped
屬性。
func swapUInt16Data(data : NSData) -> NSData {
// Copy data into UInt16 array:
let count = data.length / sizeof(UInt16)
var array = [UInt16](count: count, repeatedValue: 0)
data.getBytes(&array, length: count * sizeof(UInt16))
// Swap each integer:
for i in 0 ..< count {
array[i] = array[i].byteSwapped // *** (see below)
}
// Create NSData from array:
return NSData(bytes: &array, length: count * sizeof(UInt16))
}
如果您的實際意圖是將數據從(外部)大端表示轉換為主機(本機)字節順序(在所有當前的 iOS 和 OS X 設備上恰好是小端),那么您應該將***
替換為
array[i] = UInt16(bigEndian: array[i])
例子:
var bytes : [UInt8] = [1, 2, 3, 4, 5, 6, 7, 8]
let data = NSData(bytes: &bytes, length: bytes.count)
print(data)
// <01020304 05060708>
print(swapUInt16Data(data))
// <02010403 06050807>
Swift 3 更新:通用withUnsafeMutableBytes()
方法允許獲取UnsafeMutablePointer<UInt16>
到字節並直接修改它們:
func swapUInt16Data(data : Data) -> Data {
var mdata = data // make a mutable copy
let count = data.count / MemoryLayout<UInt16>.size
mdata.withUnsafeMutableBytes { (i16ptr: UnsafeMutablePointer<UInt16>) in
for i in 0..<count {
i16ptr[i] = i16ptr[i].byteSwapped
}
}
return mdata
}
例子:
let data = Data(bytes: [1, 2, 3, 4, 5, 6, 7, 8])
print(data as NSData) // <01020304 05060708>
let swapped = swapUInt16Data(data: data)
print(swapped as NSData) // <02010403 06050807>
CoreFoundation 具有CFSwapInt32BigToHost
和CFSwapInt32LittleToHost
等交換功能。
在swift3中它看起來像這樣
struct FileHeader {
var magicNumber: UInt32 = 0
var count: UInt32 = 0
var width: UInt32 = 0
var height: UInt32 = 0
static func create(data: Data) -> FileHeader {
let structSize = MemoryLayout<FileHeader>.size
assert(data.count >= structSize)
var result = FileHeader()
let nsdata = data as NSData
nsdata.getBytes(&result, range: NSRange(location: 0, length: structSize))
result.magicNumber = CFSwapInt32BigToHost(result.magicNumber)
result.count = CFSwapInt32BigToHost(result.count)
result.width = CFSwapInt32BigToHost(result.width)
result.height = CFSwapInt32BigToHost(result.height)
return result
}
}
對於有人可能想要限制字節模式,這將是一個解決方案:
func swap<U:IntegerType>(data:NSData,_ :U.Type) -> NSData{
var length = data.length / sizeof(U)
var bytes = [U](count: length, repeatedValue: 0)
data.getBytes(&bytes, length: data.length)
// since byteSwapped isn't declare in any protocol, so we have do it by ourselves manually.
var inverse = bytes.enumerate().reduce([U](count: length, repeatedValue: 0)) { (var pre, ele) -> [U] in
pre[length - 1 - ele.index] = ele.element
return pre
}
return NSData(bytes: inverse, length: data.length)
}
例如:
swap(data:data,UInt8.self)
//before <0c20207b 17>
//after <177b2020 0c>
swap(data:anotherData,UInt16.self)
//before <8e004c01 84008f05 0701>
//after <07018f05 84004c01 8e00>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.