1

我有以下代码可以在 Swift 5 中将一些解压Data缩回 a String。该方法大部分工作正常,但有时会失败并显示以下错误消息:

Thread 1: Fatal error: UnsafeMutablePointer.initialize overlapping range

extension Data
{
    func decompress(destinationSize: Int) -> String?
    {
        let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: destinationSize)

        let decodedString = self.withUnsafeBytes
        {
            unsafeRawBufferPointer -> String? in

            let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
            if let unsafePointer = unsafeBufferPointer.baseAddress
            {
                let decompressedSize = compression_decode_buffer(destinationBuffer, destinationSize, unsafePointer, self.count, nil, COMPRESSION_ZLIB)

                if decompressedSize == 0
                {
                    return String.empty
                }

                let string = String(cString: destinationBuffer)
                let substring = string.substring(0, decompressedSize)

                return substring
            }

            return nil
        }

        return decodedString
    }
}

错误发生在以下行:

let string = String(cString: destinationBuffer)

有人可以解释为什么这(有时)会失败吗?

4

1 回答 1

0

我已切换到以下代码,现在一切正常(Swift 5):

import Compression

extension Data
{
    func compress() -> Data?
    {
        return self.withUnsafeBytes
        {
            dataBytes in

            let sourcePtr: UnsafePointer<UInt8> = dataBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)

            return self.perform(operation: COMPRESSION_STREAM_ENCODE, source: sourcePtr, sourceSize: self.count)
        }
    }

    func decompress() -> Data?
    {
        return self.withUnsafeBytes
        {
            unsafeRawBufferPointer -> Data? in

            let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
            if let unsafePointer = unsafeBufferPointer.baseAddress
            {
                return self.perform(operation: COMPRESSION_STREAM_DECODE, source: unsafePointer, sourceSize: self.count)
            }

            return nil
        }
    }

    fileprivate func perform(operation: compression_stream_operation, source: UnsafePointer<UInt8>, sourceSize: Int, preload: Data = Data()) -> Data?
    {
        guard sourceSize > 0 else { return nil }

        let streamBase = UnsafeMutablePointer<compression_stream>.allocate(capacity: 1)
        defer { streamBase.deallocate() }
        var stream = streamBase.pointee

        let status = compression_stream_init(&stream, operation, COMPRESSION_ZLIB)
        guard status != COMPRESSION_STATUS_ERROR else { return nil }
        defer { compression_stream_destroy(&stream) }

        var result = preload
        var flags: Int32 = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
        let blockLimit = 64 * 1024
        var bufferSize = Swift.max(sourceSize, 64)

        if sourceSize > blockLimit
        {
            bufferSize = blockLimit
        }

        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        defer { buffer.deallocate() }

        stream.dst_ptr  = buffer
        stream.dst_size = bufferSize
        stream.src_ptr  = source
        stream.src_size = sourceSize

        while true
        {
            switch compression_stream_process(&stream, flags)
            {
                case COMPRESSION_STATUS_OK:
                    guard stream.dst_size == 0 else { return nil }
                    result.append(buffer, count: stream.dst_ptr - buffer)
                    stream.dst_ptr = buffer
                    stream.dst_size = bufferSize

                    if flags == 0 && stream.src_size == 0
                    {
                        flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
                    }

                case COMPRESSION_STATUS_END:
                    result.append(buffer, count: stream.dst_ptr - buffer)
                    return result

                default:
                    return nil
            }
        }
    }
}
于 2020-05-28T18:34:54.837 回答