SwiftCBOR
A CBOR (RFC 7049 Concise Binary Object Representation) decoder and encoder in Swift. Encode directly from Swift types or use a wrapper object. Decode to a CBOR value type that can be accessed with native Swift subscripting and expressed with the equivalent literal notation.
- No
Foundation
dependency! Ready for the cross-platform future of Swift. - Configured as a universal iOS / OS X framework.
- Negative integers are decoded as
NegativeInt(UInt)
, where the actual number is-1 - i
(CBOR's negative integers can be larger than 64-bit signed integers). - Tags are decoded, but not processed. Tagged values are encoded, but not type-checked. Do it yourself :-)
- Definited for the
CBOR
type! - And
subscript
too. So you can access CBOR maps and arrays like this:myDecodedObject["numbers"][1]
. - If you want to decode from a stream, implement the
CBORInputStream
protocol on your stream and create the decoder like this:CBORDecoder(stream: yourStream)
. - Half floats can be decoded to a Float. Encoding Float16s are not supported (they do not exist in Swift).
- Memory efficiency of encoding needs tuning. (Encoding is not typically done in-place.)
- Supports encoding indefinite-length data, but you need to explicitly add open and close information to your streaming data.
- cbor.me is recommended for viewing your CBOR-encoded data.
Installation
使用 Carthage。
github "myfreeweb/SwiftCBOR"
或者将其添加为 Git 子模块。
解码
import SwiftCBOR
let decoded = try! CBOR.decode([0x9f, 0x18, 255, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2, 0x18, 1, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0xff])
print(decoded)
// CBOR.array([CBOR.unsignedInt(255), CBOR.array([CBOR.unsignedInt(1), CBOR.utf8String("ABC")]), CBOR.utf8String("ABC")])
编码
编码一个值将返回一个字节数组,[UInt8]
。你可以用CBOR.encode(myValue)
或myValue.encode()
进行编码。任何符合CBOREncodable
协议的类型都可以被解码。你可以为你类型实现CBOREncodable
协议,然后像平常一样进行编码。
CBOR.encode(100) // --> [0x18, 0x64] of type [UInt8]
Int(100).encode() // --> [0x18, 0x64]. Int conforms to the CBOREncodable protocol
"hello".encode() // --> [0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f]. So does String
CBOR.encode(["a", "b", "c"])
let byteString: [UInt8] = [0x01, 0x02]
CBOR.encode(byteString, asByteString: true)
由于Swift的泛型系统不完整,你不能调用someArray.encode()
或someDictionary.encode()
,但只要你的数组元素或映射键和值类型符合CBOREncodable
,你就可以简单地使用CBOR.encode(someArrayOrMap)
。
在某些情况下,在编码之前可能需要创建CBOR
中间表示。例如,如果想要编码包含异构类型的数组或字典,如常见的JSON的对象,你不能使用原生Swift的映射。你可以实现你类型上的CBOREncodable
协议,或者构建一个CBOR
值然后编码那个值。
public protocol CBOREncodable {
func encode() -> [UInt8]
}
struct MyStruct: CBOREncodable {
var x: Int
var y: String
public func encode() -> [UInt8] {
let cborWrapper = CBOR(dictionaryLiteral:
("x", CBOR(integerLiteral: self.x)),
("y", CBOR(stringLiteral: self.y)))
return cborWrapper.encode()
}
}
MyStruct(x: 42, y: "words").encode()
// --> bytes (as hex): a2 61 79 65 77 6f 72 64 73 61 78 18 2a
当前通用API列在下面。当你需要对编码的类型有细粒度控制时,使用以下内容。
func encode<T: CBOREncodable>(_ value: T) -> [UInt8]
func encode<A: CBOREncodable, B: CBOREncodable>(_ dict: [A: B]) -> [UInt8]
// NOTE: Please see the note on encoding byte strings at the end of this readme.
func encode<T: CBOREncodable>(_ array: [T], asByteString: Bool = false) -> [UInt8]
/// Only needed for fine-grained control:
func encodeUInt{8, 16, 32, 64}(_ x: UInt8) -> [UInt8]
func encodeNegativeInt(_ x: Int) -> [UInt8]
func encodeByteString(_ bs: [UInt8]) -> [UInt8] // does no endian interpretation
func encodeString(_ str: String) -> [UInt8]
func encodeArray<T: CBOREncodable>(_ arr: [T]) -> [UInt8]
func encodeMap<A: CBOREncodable, B: CBOREncodable>(_ map: [A: B]) -> [UInt8]
func encodeTagged<T: CBOREncodable>(tag: UInt8, value: T) -> [UInt8]
func encodeSimpleValue(_ x: UInt8) -> [UInt8]
func encode{Null, Undefined, Break}() -> [UInt8]
func encodeFloat(_ x: Float) -> [UInt8]
func encodeDouble(_ x: Double) -> [UInt8]
func encodeBool(_ x: Bool) -> [UInt8]
不定长度数据
为了编码不定长度的数组、映射、字符串和字节字符串,显式使用开始和结束流CBOR值。在这两个值之间,使用已编码的数组和映射块,通过CBOR.encodeArrayChunk
和CBOR.encodeMapChunk
。不定长度的字符串和字节字符串可以正常编码(即不需要自己的'块'函数)。
let map: [String: Int] = ["a": 1]
let map2 = ["B": 2]
CBOR.encodeMapStreamStart() + CBOR.encodeMapChunk(map) + CBOR.encodeMapChunk(map2) + CBOR.encodeStreamEnd()
let bs: [UInt8] = [0xf0]
let bs2: [UInt8] = [0xff]
CBOR.encodeByteStringStreamStart()
+ CBOR.encode(bs, asByteString: true)
+ CBOR.encode(bs2, asByteString: true)
+ CBOR.encodeStreamEnd()
// Current stream-encoding API:
func encodeArrayStreamStart() -> [UInt8]
func encodeMapStreamStart() -> [UInt8]
func encodeStringStreamStart() -> [UInt8]
func encodeByteStringStreamStart() -> [UInt8]
func encodeStreamEnd() -> [UInt8] // Equal to CBOR.encodeBreak()
func encodeArrayChunk<T: CBOREncodable>(_ chunk: [T]) -> [UInt8]
func encodeMapChunk<A: CBOREncodable, B: CBOREncodable>(_ map: [A: B]) -> [UInt8]
字节序翻转注意事项
最后,在使用通用数组编码器、CBOR.encode(..)
编码字节字符串时有一些技术注意事项。如果函数参数asByteString
为true,则除了UInt8之外的所有类型数组将翻转每个元素的原始字节(但不是元素的顺序),如果计算机是little endian(CBOR使用big endian或网络字节序)。ubyte8数组被认为是已经处于网络字节序。
贡献
通过参与此项目,您同意遵守贡献者行为准则。
许可证
这是一款免费且无负担的软件,已发布到公有领域。
有关更多信息,请参阅UNLICENSE
文件或unlicense.org。