在我开始疯狂之前,我要道歉。
我正在开发实现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数组的值
答案 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是库使用的字符**。