在Swift中将UInt32数组转换为字符串字节数组

时间:2018-10-09 11:38:38

标签: swift swift4

在我开始疯狂之前,我要道歉。

我正在开发实现c库的应用程序。其中,它共享idArrays。

我有一部分对一个idArray进行解码并将其提供给我:

func decodeArrayID(aArray:UnsafeMutablePointer<CChar>, aTokenLen:UInt32)->([UInt32], String){

    let arrayCount = Int(aTokenLen / 4)
    var idArrayTemp = [UInt32]()
    var idArrayStringTemp = ""

    for i in 0..<arrayCount{

        let idValue = decodeArrayIDItem(index: i, array: aArray)

        idArrayTemp.append(idValue)
        idArrayStringTemp += "\(idValue) "

    }

    return (idArrayTemp, idArrayStringTemp)
}

func decodeArrayIDItem(index:Int, array:UnsafeMutablePointer<CChar>) -> UInt32{

    var value:UInt32 = UInt32(array[index * 4]) & 0xFF

    value <<= 8
    value |= UInt32(array [index * 4 + 1]) & 0xFF
    value <<= 8
    value |= UInt32(array [index * 4 + 2]) & 0xFF
    value <<= 8
    value |= UInt32(array [index * 4 + 3]) & 0xFF


    return value

}

我们可以看到idArray是通过UnsafeMutablePointer AKA UnsafeMutablePointer发送的。

现在,我正在处理编码部分。该函数将使用一个UInt32值数组,并将尝试将其转换为字节数组,并将转换为通过库发送的字符串。

到目前为止,我有以下代码,但它不起作用:

func encodeIDArray(idArray:[UInt32])->String{

    var aIDArray8:[UInt8] = [UInt8]()

    for var value in idArray{

        let count = MemoryLayout<UInt32>.size
        let bytePtr = withUnsafePointer(to: &value) {
            $0.withMemoryRebound(to: UInt8.self, capacity: count) {
                UnsafeBufferPointer(start: $0, count: count)
            }
        }

        aIDArray8 += Array(bytePtr)
    }

    let stringTest = String(data: Data(aIDArray8), encoding: .utf8)

    return stringTest!

}

输入[1,2]的测试结果返回“ \ u {01} \ 0 \ 0 \ 0 \ u {02} \ 0 \ 0 \ 0”,但提示不正确... < / p>

谢谢

已编辑  c函数是

DllExport void STDCALL DvProviderAvOpenhomeOrgPlaylist1EnableActionIdArray(THandle aProvider, CallbackPlaylist1IdArray aCallback, void* aPtr);

其中CallbackPlaylist1IdArray为

typedef int32_t (STDCALL *CallbackPlaylist1IdArray)(void* aPtr, IDvInvocationC* aInvocation, void* aInvocationPtr, uint32_t* aToken, char** aArray, uint32_t* aArrayLen);

aArray的值是获取Byte数组的值

4 个答案:

答案 0 :(得分:1)

您不能将二进制缓冲区转换为字符串并期望其起作用。您应该对您的二进制数据进行base64编码。这是将二进制数据表示为字符串的有效方法。

考虑以下代码:

//Utility function that takes a typed pointer to a data buffer an converts it to an array of the desired type of object
func convert<T>(count: Int, data: UnsafePointer<T>) -> [T] {
    let buffer = UnsafeBufferPointer(start: data, count: count);
    return Array(buffer)
}

//Create an array of UInt32 values
let intArray: [UInt32] = Array<UInt32>(1...10)
print("source arrray = \(intArray)")
let arraySize = MemoryLayout<UInt32>.size * intArray.count

//Convert the array to a Data object
let data = Data(bytes: UnsafeRawPointer(intArray),
                count: arraySize)

//Convert the binary Data to base64
let base64String = data.base64EncodedString()

print("Array as base64 data = ", base64String)
if let newData = Data(base64Encoded: base64String) {
    newData.withUnsafeBytes { (bytes: UnsafePointer<UInt32>)->Void in
        let newArray = convert(count:10, data: bytes)
        print("After conversion, newArray = ", newArray)
    }
} else {
    fatalError("Failed to base-64 decode data!")
}

该代码的输出为:

source arrray =[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array as base64 data =  AQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAA==
After conversion, newArray =  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Program ended with exit code: 0

答案 1 :(得分:1)

我相信您的做法正确

func encodeIDArray(idArray:[UInt32])->String{

    var aIDArray8:[UInt8] = [UInt8]()

    for var value in idArray{

        let count = MemoryLayout<UInt32>.size
        let bytePtr = withUnsafePointer(to: &value) {
            $0.withMemoryRebound(to: UInt8.self, capacity: count) { v in
                //Just change it to don't return the pointer itself, but the result of the rebound
                UnsafeBufferPointer(start: v, count: count)
            }
        }

        aIDArray8 += Array(bytePtr)
    }

    let stringTest = String(data: Data(aIDArray8), encoding: .utf8)

    return stringTest!

}

像这样在ASCII表中将测试更改为某个有效值

encodeIDArray(idArray: [65, 66, 67])   // "ABC"

我希望它对您有帮助...祝您好运,并让我知道它对您的情况有效。

答案 2 :(得分:1)

您可以将[UInt32]数组值复制到分配的内存中,而无需创建中间[Int8]数组,并使用bigEndian 属性,而不是移位和屏蔽:

func writeCArrayValue(from pointer:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?,
                      withUInt32Values array: [UInt32]){

    pointer?.pointee = UnsafeMutablePointer<Int8>.allocate(capacity: MemoryLayout<UInt32>.size * array.count)
    pointer?.pointee?.withMemoryRebound(to: UInt32.self, capacity: array.count) {
        for i in 0..<array.count {
            $0[i] = array[i].bigEndian
        }
    }
}

您可以用相同的方式进行解码:

func decodeArrayID(aArray:UnsafeMutablePointer<CChar>, aTokenLen:UInt32)->[UInt32] {

    let arrayCount = Int(aTokenLen / 4)
    var idArrayTemp = [UInt32]()

    aArray.withMemoryRebound(to: UInt32.self, capacity: arrayCount) {
        for i in 0..<arrayCount {
            idArrayTemp.append(UInt32(bigEndian: $0[i]))
        }
    }
    return idArrayTemp
}

答案 3 :(得分:0)

尽管我真的很感谢所有答案,但我终于弄清了正在发生的事情。我不得不说邓肯的答案是最接近我的问题的。

到目前为止,我已经将char **解释为String。事实证明,它也可以是指向数组的指针(如果我输入错误,请更正!)。将数组转换为String会提供该库不喜欢的格式,并且无法在另一端对其进行解码。

我最终做的方法是:

func encodeIDArray(idArray:[UInt32])->[Int8]{

    var aIDArray8 = [UInt8].init(repeating: 0, count: idArray.count*4)

    for i in 0..<idArray.count{

        aIDArray8[i * 4] = UInt8(idArray[i] >> 24) & 0xff
        aIDArray8[i * 4 + 1] = UInt8(idArray[i] >> 16) & 0xff
        aIDArray8[i * 4 + 2] = UInt8(idArray[i] >> 8) & 0xff
        aIDArray8[i * 4 + 3] = UInt8(idArray[i]) & 0xff

    }

    return aIDArray8.map { Int8(bitPattern: $0) }

}

然后像这样迅速分配C变量的值:

let myArray = encodeIDArray(idArray:theArray)
writeCArrayValue(from: aArrayPointer, withValue: myArray)

func writeCArrayValue(from pointer:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, withValue array:[Int8]){

    pointer?.pointee = UnsafeMutablePointer<Int8>.allocate(capacity: array.count)
    memcpy(pointer?.pointee, array, array.count)

}

aArrayPointer是库使用的字符**。