Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.6.0"),
],
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