Fatal error: Not enough bits to represent the passed value

Fatal error: Not enough bits to represent the passed value

尝试使用 Swift 中编写的 Mikrotik API 库: https://wiki.mikrotik.com/wiki/API_in_Swift

当我发送小命令时效果很好

但是,如果我尝试发送大脚本字符串,则会出现错误:

Fatal error: Not enough bits to represent the passed value

崩溃的代码:

private func writeLen(_ command : String) -> Data {
    let data = command.data(using: String.Encoding.utf8)
    var len = data?.count ?? 0
    var dat = Data()

    if len < 0x80 {
        dat.append([UInt8(len)], count: 1)
    }else if len < 0x4000 {
        len = len | 0x8000;
        dat.append(Data(bytes: [UInt8(len >> 8)]))
        dat.append(Data(bytes: [UInt8(len)]))
    }else if len < 0x20000 {
        len = len | 0xC00000;
        dat.append(Data(bytes: [UInt8(len >> 16)]))
        dat.append(Data(bytes: [UInt8(len >> 8)]))
        dat.append(Data(bytes: [UInt8(len)]))
    }
    else if len < 0x10000000 {
        len = len | 0xE0000000;
        dat.append(Data(bytes: [UInt8(len >> 24)]))
        dat.append(Data(bytes: [UInt8(len >> 16)]))
        dat.append(Data(bytes: [UInt8(len >> 8)]))
        dat.append(Data(bytes: [UInt8(len)]))
    }else{
        dat.append(Data(bytes: [0xF0]))
        dat.append(Data(bytes: [UInt8(len >> 24)]))
        dat.append(Data(bytes: [UInt8(len >> 16)]))
        dat.append(Data(bytes: [UInt8(len >> 8)]))
        dat.append(Data(bytes: [UInt8(len)]))
    }

    return dat
}

这部分出现致命错误:

else if len < 0x4000 {
    len = len | 0x8000;
    dat.append(Data(bytes: [UInt8(len >> 8)]))
    dat.append(Data(bytes: [UInt8(len)]))
}

行:

dat.append(Data(bytes: [UInt8(len)]))

此时数据大小为1072字节,len等于33840,无法用len值初始化UInt8。

如何编辑代码以避免错误?

我正在使用 Swift 4.2

编辑:

这里有一个相同逻辑的例子,但是写在JavaScript

module.exports.encodeString = function encodeString(s) {
var data = null;
var len = Buffer.byteLength(s);
var offset = 0;
if (len < 0x80) {
    data = new Buffer(len + 1);
    data[offset++] = len;
} else if (len < 0x4000) {
    data = new Buffer(len + 2);
    len |= 0x8000;
    data[offset++] = (len >> 8) & 0xff;
    data[offset++] = len & 0xff;
} else if (len < 0x200000) {
    data = new Buffer(len + 3);
    len |= 0xC00000;
    data[offset++] = (len >> 16) & 0xff;
    data[offset++] = (len >> 8) & 0xff;
    data[offset++] = len & 0xff;
} else if (len < 0x10000000) {
    data = new Buffer(len + 4);
    len |= 0xE0000000;
    data[offset++] = (len >> 24) & 0xff;
    data[offset++] = (len >> 16) & 0xff;
    data[offset++] = (len >> 8) & 0xff;
    data[offset++] = len & 0xff;
} else {
    data = new Buffer(len + 5);
    data[offset++] = 0xF0;
    data[offset++] = (len >> 24) & 0xff;
    data[offset++] = (len >> 16) & 0xff;
    data[offset++] = (len >> 8) & 0xff;
    data[offset++] = len & 0xff;
}
data.utf8Write(s, offset);
return data;
};

也许有人看出了区别

感谢 JavaScript 翻译。它清楚地显示了问题,因为 Swift 版本与它不相似。

让我们来看看 JavaScript 的这一段,因为它是您在 Swift 中绊倒的部分:

} else if (len < 0x4000) {
    data = new Buffer(len + 2);
    len |= 0x8000;
    data[offset++] = (len >> 8) & 0xff;
    data[offset++] = len & 0xff;
}

也就是 Swift 中的 "translated" 是这样的:

} else if len < 0x4000 {
    len = len | 0x8000;
    dat.append(Data(bytes: [UInt8(len >> 8)]))
    dat.append(Data(bytes: [UInt8(len)]))
} 

好吧,您可以立即看出它们完全不同。在最后一行,Swift 版本忘记了 & 0xff.

如果你把它放进去,一切都会开始工作。我们也可以让它看起来更像 JavaScript 原来的样子:

} else if len < 0x4000 {
    len |= 0x8000;
    dat.append(Data(bytes: [UInt8(len >> 8)]))
    dat.append(Data(bytes: [UInt8(len & 0xff)]))
}

所以我会说,是的,使用 JavaScript 作为指南,你会没事的。如果你觉得最后一行 "swifty" 不够,那么可以这样写:

    dat.append(Data(bytes: [UInt8(truncatingIfNeeded: len)]))

完全一样的结果

我不保证在您进行这些更改后一切都会完美运行(您显示的 Swift 代码在我看来仍然与 JavaScript 执行相同的操作) ,但至少我们将长度字节写入数据开头的部分将正常工作。