致命错误:没有足够的位数来表示传递的值

时间:2019-07-19 02:01:22

标签: swift mikrotik

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

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

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

  

致命错误:没有足够的位数表示传递的值

崩溃的代码:

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;
};

也许有人看到了差异

1 个答案:

答案 0 :(得分:1)

感谢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中是这样“翻译”的:

} 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作为指导,您会没事的。如果最后一行对您来说还不够“敏捷”,则可以这样写:

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

结果完全一样。

在做出这些更改后,我不能保证一切都能正常工作(显示的Swift代码对我来说似乎并不像JavaScript一样),但是至少在编写代码时数据开头的长度字节可以正常工作。