UInt32 массив в String Byte Array в Swift - PullRequest
0 голосов
/ 09 октября 2018

Прежде чем начать, я хотел бы извиниться, если скажу что-нибудь сумасшедшее.

Я работаю над приложением, которое реализует библиотеку ac.Среди прочего, он разделяет 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", и что-то говоритне совсем верно ...

Спасибо

Отредактировано Функции 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 - это значение, которое получает массив байтов

Ответы [ 4 ]

0 голосов
/ 10 октября 2018

Вы можете скопировать значения массива [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
}
0 голосов
/ 09 октября 2018

Я полагаю, что вы на правильном пути

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"

Надеюсь, это поможет вам ...Удачи, и дайте мне знать, что это работает в вашем случае.

0 голосов
/ 10 октября 2018

Хотя я действительно ценю все ответы, я наконец понял, что происходит.Я должен сказать, что ответ Дункана был самым близким к моей проблеме.

До сих пор я интерпретировал 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 в swift так:

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 - это символ **, используемый библиотекой.

0 голосов
/ 09 октября 2018

Вы не можете преобразовать двоичный буфер в строку и ожидать, что он будет работать.Вы должны 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...