简体   繁体   English

如何在 Swift 中以 littleEndian 方式字节反转 NSData 输出?

[英]How to byte reverse NSData output in Swift the littleEndian way?

I have this output from NSData: <00000100 84000c00 071490fe 4dfbd7e9>我有来自 NSData 的输出:<00000100 84000c00 071490fe 4dfbd7e9>

So how could I byte reverse it in Swift and have this output: <00000001 0084000c 1407fe90 fb4de9d7>?那么我怎么能在 Swift 中对它进行字节反转并得到这个输出:<00000001 0084000c 1407fe90 fb4de9d7>?

This should work to swap each pair of adjacent bytes in the data.这应该可以交换数据中的每对相邻字节。 The idea is to interpret the bytes as an array of UInt16 integers and use the built-in byteSwapped property.这个想法是将字节解释为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))
}

If your actual intention is to convert data from an (external) big-endian representation to the host (native) byte order (which happens to be little-endian on all current iOS and OS X devices) then you should replace *** by如果您的实际意图是将数据从(外部)大端表示转换为主机(本机)字节顺序(在所有当前的 iOS 和 OS X 设备上恰好是小端),那么您应该将***替换为

array[i] = UInt16(bigEndian: array[i])

Example:例子:

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>

Update for Swift 3: The generic withUnsafeMutableBytes() methods allows to obtain a UnsafeMutablePointer<UInt16> to the bytes and modify them directly: 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
}

Example:例子:

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 has CFSwapInt32BigToHost and CFSwapInt32LittleToHost and other swap functions. CoreFoundation 具有CFSwapInt32BigToHostCFSwapInt32LittleToHost等交换功能。

In swift3 it looks like this在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
    }
}

For someone may want to restrict the byte pattern, it would be a solution:对于有人可能想要限制字节模式,这将是一个解决方案:

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)
}

for example:例如:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM