首页 > 解决方案 > 可变字节编码方法在 Swift 中不起作用

问题描述

我正在尝试阅读此处详述的 mapsforge .map 文件,但我似乎无法使可变字节编码部分工作。只要没有第二个字节(所以数字很小),我的实现就可以工作,但是当数字编码为 2 个或更多字节时,我的函数无法正确解码。我想知道是否有人可以帮助我解决我做错了什么。

类实现:

final class MapFileInputSerializer {
    private let _0x7full: UInt64 = 0x7f
    private let _0x3full: UInt64 = 0x3f
    private let _0x3fll: Int64 = 0x3f
    private let _0xffl: Int32 = 0xff
    
    private var fileHandle: FileHandle

    init(fileUrl: URL) throws {
        let fh = try! FileHandle(forReadingFrom: fileUrl)
        fileHandle = fh
    }

    [...]

这是我知道数字是无符号整数的时候:

func readVarUInt64() throws -> UInt64 {
    var value: UInt64 = 0
    var shift: UInt = 0

    while true {
        guard let byteData = try? fileHandle.read(upToCount: 1) else { fatalError() }
        let byteValue = UInt8(bigEndian: byteData.withUnsafeBytes { $0.load(as: UInt8.self) })

        value |= (UInt64(byteValue) & _0x7full) << shift
        shift += 7

        if byteValue & 0x80 == 0 { break }
        if shift > 63 { throw Error.tooLongUInt64 }
    }

    return value
}

这是我的有符号整数函数:

func readVarInt64() -> Int64 {
    var value: Int64 = 0
    var shift: UInt = 0
    var byteValue: UInt8 = UInt8()

    while true {
        guard let byteData = try? fileHandle.read(upToCount: 1) else { fatalError() }
        byteValue = UInt8(bigEndian: byteData.withUnsafeBytes { $0.load(as: UInt8.self) })

        if byteValue & 0x80 == 0 { break } //0 at 128 means this is the last byte
        value |= Int64((UInt64(byteValue) & _0x7full) << shift)
        shift += 7
    }

    if byteValue & 0x40 != 0 { //0 at 64 means the number is positive, otherwise negative
        value = -(value | Int64(((UInt64(byteValue) & _0x3full) << shift)))
    } else {
        value |= Int64((UInt64(byteValue) & _0x3full) << shift)
    }

    return value
}

我无法真正确定错误在哪里,因为我正在解码一个巨大的文件,我只是注意到当我尝试将 UInt64 转换为 Int64 时突然出现溢出错误。调试建议也可以提供帮助。:)

标签: iosswiftmacos

解决方案


事实证明我的功能很好。我的代码中的其他地方有一个错误。由于 StackOverflow 上没有其他关于如何在 Swift 中进行可变字节编码的问题,我不会删除这个问题 - 以后可能会对某人有所帮助。


推荐阅读