Skip to content
Open
15 changes: 15 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 19 additions & 15 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
// swift-tools-version:5.5
// swift-tools-version:6.0

import PackageDescription

let package = Package(
name: "SwiftCBOR",
platforms: [.macOS(.v10_13), .iOS(.v13), .tvOS(.v13), .macCatalyst(.v13), .watchOS(.v8)],
products: [
.library(name: "SwiftCBOR", targets: ["SwiftCBOR"])
],
targets: [
.target(name: "SwiftCBOR", path: "Sources", exclude: ["Info.plist"]),
.testTarget(
name: "SwiftCBORTests",
dependencies: ["SwiftCBOR"],
path: "Tests",
exclude: ["Info.plist"]
)
]
name: "SwiftCBOR",
platforms: [.macOS(.v10_13), .iOS(.v13), .tvOS(.v13), .macCatalyst(.v13), .watchOS(.v8)],
products: [
.library(name: "SwiftCBOR", targets: ["SwiftCBOR"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-collections.git", from: "1.1.3"),
],
targets: [
.target(name: "SwiftCBOR", dependencies: [.product(name: "Collections", package: "swift-collections")],
path: "Sources", exclude: ["Info.plist"]),
.testTarget(
name: "SwiftCBORTests",
dependencies: ["SwiftCBOR"],
path: "Tests",
exclude: ["Info.plist"]
)
]
)
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
[![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](http://unlicense.org)
## SwiftCBOR (Scytales clone)


# SwiftCBOR
This is a fork of the original SwiftCBOR library based on the following [PR #96](https://github.com/valpackett/SwiftCBOR/pull/96) . The original library is available [here](https://github.com/valpackett/SwiftCBOR)


A [CBOR (RFC 7049 Concise Binary Object Representation)](http://cbor.io) 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.

Expand Down
7 changes: 4 additions & 3 deletions Sources/CBOR.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#if canImport(Foundation)
import Foundation
#endif
import OrderedCollections

public indirect enum CBOR : Equatable, Hashable,
public indirect enum CBOR : Equatable, Hashable, Sendable,
ExpressibleByNilLiteral, ExpressibleByIntegerLiteral, ExpressibleByStringLiteral,
ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral, ExpressibleByBooleanLiteral,
ExpressibleByFloatLiteral {
Expand All @@ -12,7 +13,7 @@ public indirect enum CBOR : Equatable, Hashable,
case byteString([UInt8])
case utf8String(String)
case array([CBOR])
case map([CBOR : CBOR])
case map(OrderedDictionary<CBOR,CBOR>)
case tagged(Tag, CBOR)
case simple(UInt8)
case boolean(Bool)
Expand Down Expand Up @@ -84,7 +85,7 @@ public indirect enum CBOR : Equatable, Hashable,
public init(stringLiteral value: String) { self = .utf8String(value) }
public init(arrayLiteral elements: CBOR...) { self = .array(elements) }
public init(dictionaryLiteral elements: (CBOR, CBOR)...) {
var result = [CBOR : CBOR]()
var result = OrderedDictionary<CBOR,CBOR>()
for (key, value) in elements {
result[key] = value
}
Expand Down
9 changes: 5 additions & 4 deletions Sources/CBORDecoder.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#if canImport(Foundation)
import Foundation
#endif
import OrderedCollections

public enum CBORError : Error {
case unfinishedSequence
Expand Down Expand Up @@ -81,8 +82,8 @@ public class CBORDecoder {
return result
}

private func readNPairs(_ n: Int) throws -> [CBOR : CBOR] {
var result: [CBOR: CBOR] = [:]
private func readNPairs(_ n: Int) throws -> OrderedDictionary<CBOR,CBOR> {
var result = OrderedDictionary<CBOR,CBOR>()
for _ in (0..<n) {
guard let key = try decodeItem() else { throw CBORError.unfinishedSequence }
guard let val = try decodeItem() else { throw CBORError.unfinishedSequence }
Expand All @@ -91,8 +92,8 @@ public class CBORDecoder {
return result
}

func readPairsUntilBreak() throws -> [CBOR : CBOR] {
var result: [CBOR: CBOR] = [:]
func readPairsUntilBreak() throws -> OrderedDictionary<CBOR,CBOR> {
var result = OrderedDictionary<CBOR,CBOR>()
var key = try decodeItem()
if key == CBOR.break {
return result
Expand Down
16 changes: 14 additions & 2 deletions Sources/CBOREncodable.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#if canImport(Foundation)
import Foundation
#endif
import OrderedCollections

public protocol CBOREncodable {
/// Optional function that can potentially serve as an opportunity to optimize encoding.
Expand All @@ -25,7 +26,7 @@ extension CBOR: CBOREncodable {
case let .byteString(bs): return CBOR.encodeByteString(bs, options: options)
case let .utf8String(str): return str.encode(options: options)
case let .array(a): return CBOR.encodeArray(a, options: options)
case let .map(m): return CBOR.encodeMap(m, options: options)
case let .map(m): return CBOR.encodeCBORMap(m, options: options)
#if canImport(Foundation)
case let .date(d): return CBOR.encodeDate(d, options: options)
#endif
Expand Down Expand Up @@ -210,10 +211,21 @@ extension Dictionary where Key: CBOREncodable, Value: CBOREncodable {
}

public func toCBOR(options: CBOROptions = CBOROptions()) -> CBOR {
return CBOR.map(Dictionary<CBOR, CBOR>(uniqueKeysWithValues: self.map { ($0.key.toCBOR(options: options), $0.value.toCBOR(options: options)) }))
return CBOR.map(OrderedDictionary<CBOR, CBOR>(uniqueKeysWithValues: self.map { ($0.key.toCBOR(options: options), $0.value.toCBOR(options: options)) }))
}
}


extension OrderedDictionary where Key: CBOREncodable, Value: CBOREncodable {
public func encode(options: CBOROptions = CBOROptions()) -> [UInt8] {
return CBOR.encodeCBORMap(OrderedDictionary<CBOR, CBOR>(uniqueKeysWithValues: self.map { ($0.key.toCBOR(options: options), $0.value.toCBOR(options: options)) }), options: options)
}

public func toCBOR(options: CBOROptions = CBOROptions()) -> CBOR {
return CBOR.map(OrderedDictionary<CBOR, CBOR>(uniqueKeysWithValues: self.map { ($0.key.toCBOR(options: options), $0.value.toCBOR(options: options)) }))
}
}

extension Optional where Wrapped: CBOREncodable {
public func encode(options: CBOROptions = CBOROptions()) -> [UInt8] {
switch self {
Expand Down
27 changes: 24 additions & 3 deletions Sources/CBOREncoder.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#if canImport(Foundation)
import Foundation
#endif
import OrderedCollections

let isBigEndian = Int(bigEndian: 42) == 42

Expand Down Expand Up @@ -170,6 +171,14 @@ extension CBOR {
try CBOR.encodeMap(map, into: &res, options: options)
return res
}

public static func encodeCBORMap(_ map: OrderedDictionary<CBOR, CBOR>, options: CBOROptions = CBOROptions()) -> [UInt8] {
var res: [UInt8] = []
res = map.count.encode(options: options)
res[0] = res[0] | 0b101_00000
CBOR.encodeCBORMap(map, into: &res, options: options)
return res
}

// MARK: - major 6: tagged values

Expand Down Expand Up @@ -273,7 +282,8 @@ extension CBOR {
let (integral, fractional) = modf(timeInterval)

let seconds = Int64(integral)
let nanoseconds = Int32(fractional * Double(NSEC_PER_SEC))
// The NSEC_PER_SEC value is 1,000,000,000 (one billion), representing the number of nanoseconds in one second.
let nanoseconds = Int32(fractional * Double(1_000_000_000))

switch options.dateStrategy {
case .annotatedMap:
Expand All @@ -288,7 +298,7 @@ extension CBOR {
dateCBOR = CBOR.unsignedInt(UInt64(seconds))
}

let map: [String: CBOREncodable] = [
let map: Dictionary<String, Any?> = [
AnnotatedMapDateStrategy.typeKey: AnnotatedMapDateStrategy.typeValue,
AnnotatedMapDateStrategy.valueKey: dateCBOR
]
Expand Down Expand Up @@ -422,7 +432,7 @@ extension CBOR {
return try CBOR.array(anyArr.map { try cborFromAny($0) })
case is [String: Any?]:
let anyMap = any as! [String: Any?]
return try CBOR.map(Dictionary(
return try CBOR.map(OrderedDictionary(
uniqueKeysWithValues: anyMap.map { try (cborFromAny($0.key), cborFromAny($0.value)) }
))
case is Void:
Expand Down Expand Up @@ -479,6 +489,17 @@ extension CBOR {
}
}
}

private static func encodeCBORMap(_ map: OrderedDictionary<CBOR, CBOR>, into res: inout [UInt8], options: CBOROptions = CBOROptions()) {
let sortedKeysWithEncodedKeys = map.keys

sortedKeysWithEncodedKeys.forEach { keyTuple in
let encodedKey = keyTuple.encode(options: options)
res.append(contentsOf: encodedKey)
let encodedVal = map[keyTuple]!.encode(options: options)
res.append(contentsOf: encodedVal)
}
}
}

public enum CBOREncoderError: Error {
Expand Down
4 changes: 3 additions & 1 deletion Tests/CBOREncodableTests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import XCTest
@testable import SwiftCBOR
import OrderedCollections

class CBOREncodableTests: XCTestCase {
func testToCBOR() {
Expand Down Expand Up @@ -58,9 +59,10 @@ class CBOREncodableTests: XCTestCase {

XCTAssertEqual(CBOR.array([CBOR.unsignedInt(1), CBOR.unsignedInt(2)]), [1, 2].toCBOR(options: CBOROptions()))

let orderedDict: OrderedDictionary<CBOR,CBOR> = ["a": 1, "b": 2]
XCTAssertEqual(
CBOR.map([CBOR.utf8String("a"): CBOR.unsignedInt(1), CBOR.utf8String("b"): CBOR.unsignedInt(2)]),
["a": 1, "b": 2].toCBOR(options: CBOROptions())
orderedDict.toCBOR(options: CBOROptions())
)
}
}
3 changes: 2 additions & 1 deletion Tests/CBORTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import XCTest
import OrderedCollections
@testable import SwiftCBOR

class CBORTests: XCTestCase {
Expand Down Expand Up @@ -50,7 +51,7 @@ class CBORTests: XCTestCase {
let cborEncoded: [UInt8] = try! CBOR.encodeMap(dictionary)
var cbor = try! CBOR.decode(cborEncoded)!

let nestedMap: [CBOR: CBOR] = [
let nestedMap: OrderedDictionary<CBOR, CBOR> = [
"joe": "schmoe",
"age": 56
]
Expand Down