├── .DS_Store
├── .swift-version
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── SwiftMsgPack
│ ├── Commons.swift
│ ├── Decoder.swift
│ └── Encoder.swift
├── SwiftMsgPack.podspec
├── SwiftMsgPack
├── SwiftMsgPack.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ ├── dan.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ │ │ └── danielemm.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── SwiftMsgPack.xcscheme
│ └── xcuserdata
│ │ └── danielemm.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── SwiftMsgPack
│ ├── Info.plist
│ └── SwiftMsgPack.h
└── SwiftMsgPackTests
│ └── Info.plist
├── Tests
├── .DS_Store
└── SwiftMsgPackTests
│ ├── SwiftMsgPackTests_Array.swift
│ ├── SwiftMsgPackTests_BoolNil.swift
│ ├── SwiftMsgPackTests_Data.swift
│ ├── SwiftMsgPackTests_Dictionary.swift
│ ├── SwiftMsgPackTests_Numeric.swift
│ └── SwiftMsgPackTests_String.swift
└── banner.png
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/SwiftMsgPack/6a9b7d73f78cd0f7e5ad280fde39a347f15baaf7/.DS_Store
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.0
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Daniele Margutti
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "SwiftMsgPack",
6 | products: [
7 | .library(name: "SwiftMsgPack", targets: ["SwiftMsgPack"])
8 | ],
9 | targets: [
10 | .target(name: "SwiftMsgPack"),
11 | .testTarget(
12 | name: "SwiftMsgPackTests",
13 | dependencies: ["SwiftMsgPack"]
14 | ),
15 | ]
16 | )
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | It's like JSON, but faster!
6 |
7 |
8 | [](https://github.com/Carthage/Carthage) [](https://travis-ci.org/malcommac/SwiftMsgPack) [](http://cocoadocs.org/docsets/SwiftMsgPack) [](http://cocoadocs.org/docsets/SwiftMsgPack) [](http://cocoadocs.org/docsets/SwiftMsgPack)
9 |
10 | ## What's this?
11 |
12 | [MessagePack](http://msgpack.org/) is an efficient binary serialization format, which lets you exchange data among multiple languages like JSON, except that it's [faster and smaller](http://theburningmonk.com/2011/12/performance-test-binary-serializers-part-ii). Small integers are encoded into a single byte while typical short strings require only one extra byte in addition to the strings themselves.
13 | You can read more about [specs directly from the main web](https://github.com/msgpack/msgpack/blob/master/spec.md) site.
14 | Moreover it's made in pure Swift, no dependencies, lightweight & fully portable
15 |
16 | ## Your Support
17 |
18 | *Hi fellow developer!*
19 | You know, maintaing and developing tools consumes resources and time. While I enjoy making them **your support is foundamental to allow me continue its development**.
20 |
21 | If you are using SwiftLocation or any other of my creations please consider the following options:
22 |
23 | - [**Make a donation with PayPal**](https://www.paypal.com/paypalme/danielemargutti/20)
24 | - [**Become a Sponsor**](https://github.com/sponsors/malcommac)
25 |
26 | - [⭐️ Follow Me & Discover Other Projects](https://github.com/malcommac)
27 |
28 | ## Index
29 | * **[How to use](#howto)**
30 | * **[Supported Types](#supportedtypes)**
31 | * **[Installation (CocoaPods, SwiftPM and Carthage)](#installation)**
32 | * **[Tests](#tests)**
33 |
34 |
35 |
36 | ## How to use: one-shot pack & unpack
37 |
38 | Both serialization and deseralization happens inside a `Data` object.
39 |
40 | In order to pack one or more objects you need to create an empty `Data` instance and call `pack` by passing the object(s) you want to serialize.
41 | It's pretty easy, take a look here:
42 |
43 | ```swift
44 | var data = Data()
45 | do {
46 | let obj1 = "Hello World"
47 | let obj2 = 45.5
48 | let obj3: [AnyHashable:Any?] = [ "key_1" : "value test","key_2" : 4,"key_3" : true, otherHashableKey: "value1"]
49 | // Now you can pack your instances by passing them to pack function
50 | try data.pack(obj1,obj2,obj3)
51 | } catch {
52 | print("Something went wrong while packing data: \(error)")
53 | }
54 | ```
55 |
56 | Deserializing data is pretty simple too, just call `unpack` function to an instance of `Data` with msgpack data:
57 |
58 | ```swift
59 | let data: Data = // msgpack data...
60 | do {
61 | let decodedObj: Any? = try data.unpack()
62 | } catch {
63 | print("Something went wrong while unpacking data: \(error)")
64 | }
65 | ```
66 |
67 |
68 |
69 | ## Supported Types
70 |
71 | SwiftMsgPack supports the following Swift types:
72 | - `String`
73 | - `Data`
74 | - `Bool`
75 | - `nil`
76 | - Numeric values: `Int` & `UInt` (`UInt8`,`Int8`,`UInt16`,`Int16`,`UInt32`,`Int32`,`UInt64`,`Int64`), `Float` and `Double`
77 | - `Dictionaries` (`[AnyHashable:Any?]`)
78 | - `Array` (`[Any?]`)
79 |
80 | The following limitations are specified by [MsgPack specs format](https://github.com/msgpack/msgpack/blob/master/spec.md#types-limitation):
81 |
82 | * a value of an Integer object is limited from `-(2^63)` upto `(2^64)-1`
83 | * maximum length of a Binary object is `(2^32)-1`
84 | * maximum byte size of a String object is `(2^32)-1`
85 | * String objects may contain invalid byte sequence and the behavior of a deserializer depends on the actual implementation when it received invalid byte sequence
86 | * Deserializers should provide functionality to get the original byte array so that applications can decide how to handle the object
87 | * maximum number of elements of an Array object is `(2^32)-1`
88 | * maximum number of key-value associations of a Map object is `(2^32)-1`
89 |
90 |
91 |
92 | ## Installation
93 | You can install Swiftline using CocoaPods, carthage and Swift package manager
94 |
95 | ### CocoaPods
96 | use_frameworks!
97 | pod 'SwiftMsgPack'
98 |
99 | ### Carthage
100 | github 'malcommac/SwiftMsgPack'
101 |
102 | ### Swift Package Manager
103 | Add swiftline as dependency in your `Package.swift`
104 |
105 | ```
106 | import PackageDescription
107 |
108 | let package = Package(name: "YourPackage",
109 | dependencies: [
110 | .Package(url: "https://github.com/malcommac/SwiftMsgPack.git", majorVersion: 0),
111 | ]
112 | )
113 | ```
114 |
115 |
116 |
117 | ## Tests
118 |
119 | SwiftMsgPack has an extensive coverage using XCTest.
120 | You can found a complete list of tests inside `Tests/SwiftMsgPackTests` folder.
121 | Tests can also be runned with XCode using the SwiftMsgPack project.
122 |
123 |
124 |
125 | ## Contributing
126 |
127 | - If you **need help** or you'd like to **ask a general question**, open an issue.
128 | - If you **found a bug**, open an issue.
129 | - If you **have a feature request**, open an issue.
130 | - If you **want to contribute**, submit a pull request.
131 |
132 | ## Copyright & Acknowledgements
133 |
134 | SwiftLocation is currently owned and maintained by Daniele Margutti.
135 | You can follow me on Twitter [@danielemargutti](http://twitter.com/danielemargutti).
136 | My web site is [https://www.danielemargutti.com](https://www.danielemargutti.com)
137 |
138 | This software is licensed under [MIT License](LICENSE.md).
139 |
140 | ***Follow me on:***
141 | - 💼 [Linkedin](https://www.linkedin.com/in/danielemargutti/)
142 | - 🐦 [Twitter](https://twitter.com/danielemargutti)
143 |
--------------------------------------------------------------------------------
/Sources/SwiftMsgPack/Commons.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 | import Foundation
34 |
35 | /// Error MsgPack encoder/decoder may generate during the elaboration of the data
36 | ///
37 | /// - invalidEncoding: invalid encoding. string cannot be encoded correctly in UTF-8
38 | /// - unexpectedData: missing data
39 | /// - dataIsTooBig: data is too large to be contained in a MsgPack data (see https://github.com/msgpack/msgpack/blob/master/spec.md#types-limitation)
40 | /// - unsupportedValue: unsupported value
41 | public enum MsgPackError: Error {
42 | case invalidEncoding
43 | case unexpectedData
44 | case dataIsTooBig(_: String)
45 | case unsupportedValue(_: Any)
46 | }
47 |
48 | // This enum defines the prefix header bytes to write
49 | // according to the MsgPack specs
50 | // https://github.com/msgpack/msgpack/blob/master/spec.md#formats-bool
51 | public enum MsgPackType: CustomStringConvertible {
52 |
53 | // numeric vlues
54 | case uInt64
55 | case int64
56 | case uInt32
57 | case int32
58 | case uInt16
59 | case int16
60 | case uInt8
61 | case pFixInt8(value: Int)
62 | case nFixInt(value: Int)
63 | case nInt8
64 | case nInt16
65 | case nInt32
66 | case nInt64
67 | case float
68 | case double
69 | case fixstr
70 | // string
71 | case str(length: Int)
72 | // binary data
73 | case bin8
74 | case bin16
75 | case bin32
76 | // array
77 | case array(items: Int)
78 | case fixarray(items: Int)
79 | case array16
80 | case array32
81 | // dictionary
82 | case dict(items: Int)
83 | case fixdict(items: Int)
84 | case dict16
85 | case dict32
86 | // nil
87 | case `nil`
88 | // bool
89 | case boolean(_: Bool)
90 |
91 | /// The `UInt8` which represent the type of data
92 | public func value() throws -> UInt8 {
93 | switch self {
94 |
95 | // numeric values
96 | case .uInt64: return UInt8(0xcf) // uint 64 11001111 0xcf
97 | case .int64: return UInt8(0xd3) // int 64 11010011 0xd3
98 | case .uInt32: return UInt8(0xce) // uint 32 11001110 0xce
99 | case .int32: return UInt8(0xd2) // int 32 11010010 0xd2
100 | case .uInt16: return UInt8(0xcd) // uint 16 11001101 0xcd
101 | case .int16: return UInt8(0xd1) // int 16 11010001 0xd1
102 | case .uInt8: return UInt8(0xcc) // uint 8 11001100 0xcc
103 | case .pFixInt8(let value): return UInt8(value & 0x7f) // positive fixint 0xxxxxxx 0x00 - 0x7f
104 | case .nFixInt(let value): return UInt8(value & 0xff) // negative fixint 111xxxxx 0xe0 - 0xff
105 | case .nInt8: return UInt8(0xd0) // int 8 11010000 0xd0
106 | case .nInt16: return UInt8(0xd1) // int 16 11010001 0xd1
107 | case .nInt32: return UInt8(0xd2) // int 32 11010010 0xd2
108 | case .nInt64: return UInt8(0xd3) // int 64 11010011 0xd3
109 | case .float: return UInt8(0xca) // float 32 11001010 0xca
110 | case .double: return UInt8(0xcb) // float 64 11001011
111 |
112 | // binary data
113 | case .bin8: return UInt8(0xc4) // bin 8 11000100 0xc4
114 | case .bin16: return UInt8(0xc5) // bin 16 11000101 0xc5
115 | case .bin32: return UInt8(0xc6) // bin 32 11000110 0xc6
116 |
117 | // array
118 | case .fixarray(let count): return UInt8(0x90 + count) // fixarray 1001xxxx 0x90 - 0x9f
119 | case .array16: return UInt8(0xdc) // array 16 11011100 0xdc
120 | case .array32: return UInt8(0xdd) // array 32 11011101 0xdd
121 | case .array(let count):
122 | if count < 16 { // less than 16 bit length
123 | return try MsgPackType.fixarray(items: count).value()
124 | }
125 | else if count < Int(UInt16.max) { // 16 bit length
126 | return try MsgPackType.array16.value()
127 | }
128 | else { //if count < Int(UInt32.max) { // 32 bit length
129 | return try MsgPackType.array32.value()
130 | }
131 | //throw MsgPackError.dataIsTooBig("Array is too big: \(count) items")
132 |
133 | // string
134 | case .fixstr: return UInt8(0xa0) // fixstr 101xxxxx 0xa0 - 0xbf
135 | case .str(let length):
136 | if length < 32 {
137 | // 0xa0 + length of the string
138 | return UInt8(try MsgPackType.fixstr.value() + UInt8(length))
139 | }
140 | else if length < Int(UInt8.max) {
141 | // str 8 11011001 0xd9
142 | return UInt8(0xd9)
143 | }
144 | else if length < Int(UInt16.max) {
145 | // str 16 11011010 0xda
146 | return UInt8(0xda)
147 | }
148 | else { //if length < Int(UInt32.max) {
149 | // str 32 11011011 0xdb
150 | return UInt8(0xdb)
151 | }
152 | //throw MsgPackError.dataIsTooBig("String is too long: \(length) chars")
153 |
154 | // dictionaries
155 | case .fixdict(let count): return UInt8(0x80 + count) // fixmap 1000xxxx 0x80 - 0x8f
156 | case .dict16: return UInt8(0xde) // map 16 11011110 0xde
157 | case .dict32: return UInt8(0xdf) // map 32 11011111 0xdf
158 | case .dict(let count):
159 | if count < 16 { // less than 16 bit
160 | return try MsgPackType.fixdict(items: count).value()
161 | }
162 | else if count < Int(UInt16.max) { // 16 bit
163 | return try MsgPackType.dict16.value()
164 | }
165 | else { //if count < Int(UInt32.max) { // 32 bit
166 | return try MsgPackType.dict32.value()
167 | }
168 | //throw MsgPackError.dataIsTooBig("Dictionary is too big: \(count) keys")
169 |
170 | // nil values
171 | case .nil: return UInt8(0xc0)
172 |
173 | // boolean values
174 | case .boolean(let v): return UInt8(v ? 0xc3 : 0xc2)
175 | }
176 | }
177 |
178 | /// String representation
179 | public var description: String {
180 | switch self {
181 | case .uInt64: return "uInt64"
182 | case .int64: return "int64"
183 | case .uInt32: return "uInt32"
184 | case .int32: return "int32"
185 | case .uInt16: return "uInt16"
186 | case .int16: return "int16"
187 | case .uInt8: return "uInt8"
188 | case .pFixInt8(let value): return "pFixInt8 (val= \(value))"
189 | case .nFixInt(let value): return "pFixInt8 (val= \(value))"
190 | case .nInt8: return "nInt8"
191 | case .nInt16: return "nInt16"
192 | case .nInt32: return "nInt32"
193 | case .nInt64: return "nInt64"
194 | case .float: return "float"
195 | case .double: return "double"
196 | case .fixstr: return "fixstr"
197 | case .str(let len): return "str (len= \(len))"
198 | case .bin8: return "bin8"
199 | case .bin16: return "bin16"
200 | case .bin32: return "bin32"
201 | case .array(let count): return "array (count= \(count))"
202 | case .fixarray(let count): return "fixarray (count= \(count))"
203 | case .array16: return "array16"
204 | case .array32: return "array32"
205 | case .dict(let count): return "dict (keys= \(count))"
206 | case .fixdict(let count): return "fixdict (keys= \(count))"
207 | case .dict16: return "dict16"
208 | case .dict32: return "dict32"
209 | case .`nil`: return "nil"
210 | case .boolean(let val): return "bool (is true=\(val))"
211 |
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/Sources/SwiftMsgPack/Decoder.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 | import Foundation
34 |
35 | // MARK: Helper Struct to read and decoded stream of `Data`
36 |
37 | private struct StreamReader {
38 |
39 | /// Pointer to `data` instance
40 | private var data: Data
41 |
42 | /// Current position on `data` instance
43 | private var index: Int
44 |
45 | /// Initialize a new stream with an input data
46 | ///
47 | /// - Parameter data: data to read
48 | public init(_ data: Data) {
49 | self.data = data
50 | self.index = 0
51 | }
52 |
53 | /// Read the next data type header of the structure (8 bit) and move the index by 1 position
54 | ///
55 | /// - Returns: data type value
56 | /// - Throws: throw an exception if data cannot be read or it's not available
57 | mutating func readType() throws -> UInt8 {
58 | guard index < data.count else {
59 | throw MsgPackError.unexpectedData
60 | }
61 | let type: UInt8 = data[Data.Index(index)]
62 | index += 1
63 | return type
64 | }
65 |
66 | /// Read 8 bit value and return it and move the index by 1 position
67 | ///
68 | /// - Returns: 8 bit value
69 | /// - Throws: throw an exception if data cannot be read or it's not available
70 | mutating func read8Bit() throws -> UInt8 {
71 | return try readType()
72 | }
73 |
74 |
75 | /// Read next 16 bytes and return the value (index is moved according to the task)
76 | ///
77 | /// - Returns: value read
78 | /// - Throws: throw an exception if data cannot be read or it's not available
79 | mutating func read16Bit() throws -> UInt16 {
80 | guard index + 2 <= data.count else {
81 | throw MsgPackError.unexpectedData
82 | }
83 | let value_int16 = UInt16(data[Data.Index(index)]) << 8 + UInt16(data[Data.Index(index + 1)])
84 | index += 2
85 | return value_int16
86 | }
87 |
88 | /// Read next 32 bytes and return the value (index is moved according to the task)
89 | ///
90 | /// - Returns: value read
91 | /// - Throws: throw an exception if data cannot be read or it's not available
92 | mutating func read32Bit() throws -> UInt32 {
93 | guard index + 4 <= data.count else {
94 | throw MsgPackError.unexpectedData
95 | }
96 | var value_int32: UInt32 = 0
97 | for idx in index...(index + 3) {
98 | value_int32 = (value_int32 << 8) + UInt32(data[Data.Index(idx)])
99 | }
100 | index += 4
101 | return value_int32
102 | }
103 |
104 | /// Read next 64 bytes and return the value (index is moved according to the task)
105 | ///
106 | /// - Returns: value read
107 | /// - Throws: throw an exception if data cannot be read or it's not available
108 | mutating func read64Bit() throws -> UInt64 {
109 | guard index + 8 <= data.count else {
110 | throw MsgPackError.unexpectedData
111 | }
112 | var value_int64: UInt64 = 0
113 | for idx in index...(index + 7) {
114 | value_int64 = (value_int64 << 8) + UInt64(data[Data.Index(idx)])
115 | }
116 | index += 8
117 | return value_int64
118 | }
119 |
120 |
121 | /// Read next `length` bytes of data and return it (index is moved according to it)
122 | ///
123 | /// - Parameter length: length of data to read
124 | /// - Returns: read value
125 | /// - Throws: throw an exception if data cannot be read or it's not available
126 | mutating func readData(length: Int) throws -> Data {
127 | guard index + length <= data.count else {
128 | throw MsgPackError.unexpectedData
129 | }
130 | let range = index ..< (index + length)
131 | index += length
132 | return data.subdata(in: range)
133 | }
134 | }
135 |
136 | // MARK: Unpack of MsgPack Data
137 |
138 | public extension Data {
139 |
140 | // MARK - Unpack
141 |
142 | /// This is the public function which can read a sequence of Data
143 | /// and unpack all objects by returning decoded data.
144 | ///
145 | /// - Returns: decoded data
146 | /// - Throws: an error if decoding task cannot be finished correctly due to an error
147 | func unpack() throws -> Any? {
148 | // Create a reader which has a point to the current position in data instance
149 | // and several help functions to read data
150 | var reader = StreamReader(self)
151 | // try to unpack data
152 | return try self.unpack(stream: &reader)
153 | }
154 |
155 | // MARK - Unpack Internal Functions
156 |
157 | /// This is the unpack function which reader
158 | ///
159 | /// - Parameter stream: stream object
160 | /// - Returns: decoded data
161 | /// - Throws: an error if decoding task cannot be finished correctly due to an error
162 | private func unpack(stream: inout StreamReader) throws -> Any? {
163 | let type = try stream.readType()
164 |
165 | // Spec is defined here:
166 | // https://github.com/msgpack/msgpack/blob/master/spec.md#formats-bool
167 | switch type {
168 |
169 | // POSITIVE FIX INT
170 | // positive fixint 0xxxxxxx 0x00 - 0x7f
171 | case 0x00...0x7f:
172 | return Int8(type)
173 |
174 | // FIX DICTIONARY (< 16 ITEMS)
175 | // fixmap 1000xxxx 0x80 - 0x8f
176 | case 0x80...0x8f:
177 | let count_items = Int(type & 0xf)
178 | return try self.unpack(dictionary: &stream, count: count_items)
179 |
180 | // FIX ARRAY (< 16 ITEMS)
181 | // fixarray 1001xxxx 0x90 - 0x9f
182 | case 0x90...0x9f:
183 | let count_items = Int(type & 0xf)
184 | return try self.unpack(array: &stream, count: count_items)
185 |
186 | // NEGATIVE FIX NUM
187 | // negative fixint 111xxxxx 0xe0 - 0xff
188 | case 0xe0...0xff:
189 | return Int8( Int(type) - 256)
190 |
191 | // FIX STRING (< 16 CHARS)
192 | // fixstr 101xxxxx 0xa0 - 0xbf
193 | case 0xa0...0xbf:
194 | let str_length = Int(type - 0xa0)
195 | return try self.unpack(string: &stream, length: str_length)
196 |
197 | // NIL VALUE
198 | // nil 11000000 0xc0
199 | case 0xc0:
200 | return nil
201 |
202 | // BOOLEAN FALSE
203 | // false 11000010 0xc2
204 | case 0xc2:
205 | return false
206 |
207 | // BOOLEAN TRUE
208 | // true 11000011 0xc3
209 | case 0xc3:
210 | return true
211 |
212 | // BINARY DATA 8 BIT
213 | // bin 8 11000100 0xc4
214 | case 0xc4:
215 | let len_data = Int(try stream.read8Bit())
216 | return try stream.readData(length: len_data)
217 |
218 | // BINARY DATA 16 BIT
219 | // bin 16 11000101 0xc5
220 | case 0xc5:
221 | let len_data = Int(try stream.read16Bit())
222 | return try stream.readData(length: len_data)
223 |
224 | // BINARY DATA 32 BIT
225 | // bin 32 11000110 0xc6
226 | case 0xc6:
227 | let len_data = Int(try stream.read32Bit())
228 | return try stream.readData(length: len_data)
229 |
230 | // FLOAT 32 BIT
231 | // float 32 11001010 0xca
232 | case 0xca:
233 | return Float(bitPattern: try stream.read32Bit())
234 |
235 | // DOUBLE
236 | // float 64 11001011 0xcb
237 | case 0xcb:
238 | return Double(bitPattern: try stream.read64Bit())
239 |
240 | // UNSIGNED INT 8 BIT
241 | // uint 8 11001100 0xcc
242 | case 0xcc:
243 | return try stream.readType()
244 |
245 | // UNSIGNED INT 16 BIT
246 | // uint 16 11001101 0xcd
247 | case 0xcd:
248 | let h = UInt16(try stream.read8Bit())
249 | let l = UInt16(try stream.read8Bit())
250 | return (h << 8 + l)
251 |
252 | // UNSIGNED INT 32 BIT
253 | // uint 32 11001110 0xce
254 | case 0xce:
255 | return try stream.read32Bit()
256 |
257 | // UNSIGNED INT 64 BIT
258 | // uint 64 11001111 0xcf
259 | case 0xcf:
260 | return try stream.read64Bit()
261 |
262 | // INT 8 BIT
263 | // int 8 11010000 0xd0
264 | case 0xd0:
265 | let value = try stream.read8Bit()
266 | return Int8(Int(value) - 256)
267 |
268 | // INT 16 BIT
269 | // int 16 11010001 0xd1
270 | case 0xd1:
271 | let h = UInt16(try stream.read8Bit())
272 | let l = UInt16(try stream.read8Bit())
273 | return Int16(bitPattern: h << 8 + l)
274 |
275 | // INT 32 BIT
276 | // int 32 11010010 0xd2
277 | case 0xd2:
278 | return try Int32(bitPattern: stream.read32Bit())
279 |
280 | // INT 64 BIT
281 | // int 64 11010011 0xd3
282 | case 0xd3:
283 | return try Int64(bitPattern: stream.read64Bit())
284 |
285 | // STRING 8 BIT LENGTH
286 | // str 8 11011001 0xd9
287 | case 0xd9:
288 | let len_data = Int(try stream.read8Bit())
289 | return try unpack(string: &stream, length: len_data)
290 |
291 | // STRING 16 BIT LENGTH
292 | // str 16 11011010 0xda
293 | case 0xda:
294 | let len_data = Int(try stream.read8Bit()) << 8 + Int(try stream.read8Bit())
295 | return try unpack(string: &stream, length: len_data)
296 |
297 | // STRING 32 BIT LENGTH
298 | // str 32 11011011 0xdb
299 | case 0xdb:
300 | var len_data = Int(try stream.read8Bit()) << 24
301 | len_data += Int(try stream.read8Bit()) << 16
302 | len_data += Int(try stream.read8Bit()) << 8
303 | len_data += Int(try stream.read8Bit())
304 | return try unpack(string: &stream, length: len_data)
305 |
306 |
307 | // ARRAY 16 ITEMS LENGTH
308 | // array 16 11011100 0xdc
309 | case 0xdc:
310 | let count_items = Int(try stream.read16Bit())
311 | return try unpack(array: &stream, count: count_items)
312 |
313 | // ARRAY 32 ITEMS LENGTH
314 | // array 32 11011101 0xdd
315 | case 0xdd:
316 | let count_items = Int(try stream.read32Bit())
317 | return try unpack(array: &stream, count: count_items)
318 |
319 | // DICTIONARY 16 ITEMS LENGTH
320 | // map 16 11011110 0xde
321 | case 0xde:
322 | let count_items = Int(try stream.read16Bit())
323 | return try unpack(dictionary: &stream, count: count_items)
324 |
325 | // DICTIONARY 32 ITEMS LENGTH
326 | // map 32 11011111 0xdf
327 | case 0xdf:
328 | let count_items = Int(try stream.read32Bit())
329 | return try unpack(dictionary: &stream, count: count_items)
330 |
331 | default:
332 | throw MsgPackError.unsupportedValue(String(format: "Type(%02x)", type))
333 | }
334 | }
335 |
336 | /// Unpack a `dictionary` sequence
337 | ///
338 | /// - Parameters:
339 | /// - stream: input stream of data
340 | /// - count: number of keys in dictionary
341 | /// - Returns: decoded dictionary
342 | /// - Throws: throw an exception if failed to decoded data
343 | private func unpack(dictionary stream: inout StreamReader, count: Int) throws -> [AnyHashable: Any?] {
344 | var dict: [AnyHashable: Any?] = [:]
345 | for _ in 0.. [Any?] {
363 | var array: [Any?] = []
364 | for _ in 0.. String {
379 | let data = try stream.readData(length: length)
380 | guard let str = String(data: data, encoding: String.Encoding.utf8) else {
381 | throw MsgPackError.invalidEncoding
382 | }
383 | return str
384 | }
385 |
386 | }
387 |
--------------------------------------------------------------------------------
/Sources/SwiftMsgPack/Encoder.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 | import Foundation
34 |
35 |
36 | // MARK: - Pack
37 |
38 | public extension Data {
39 |
40 | // MARK: - Pack functions
41 |
42 | /// Allows you to pack multiple objects passed as input.
43 | /// See `pack(_ obj:Any?)` for more info about supported formats.
44 | ///
45 | /// - Parameter objects: objects to pack
46 | /// - Returns: `self` `(maybe used to chain multiple pack`)
47 | /// - Throws: throw an exception if packing fails for some reason
48 | @discardableResult
49 | mutating func pack(_ objects: Any?...) throws -> Data {
50 | try objects.forEach { try self.pack($0) }
51 | return self
52 | }
53 |
54 | /// This is the main func used to pack an object.
55 | /// Packing is done by mutating `self` instance of `Data` caller of the function.
56 | /// Recognized types includes:
57 | /// `String`,`UInt8`,`UInt16`,`UInt32`,`UInt64`,`Int8`,`Int16`,`Int32`,`Int64`,
58 | /// `Double`,`Float`,`Int`,`UInt`,`Character`,`Bool`,`Array` and `Dictionary`.
59 | /// Also nil objects are accepted and encoded according to the msgpack format.
60 | ///
61 | /// - Parameter obj: object to pack or `nil`
62 | /// - Returns: `self` `(maybe used to chain multiple pack`)
63 | /// - Throws: throw an exception if packing fails for some reason
64 | @discardableResult
65 | mutating func pack(_ obj: Any?) throws -> Data {
66 |
67 | guard let obj = obj else {
68 | // If the object is nil we want to write the nil
69 | // msgpack prefix (0xc0)
70 | try self.writeDataTypeHeader(.nil)
71 | return self
72 | }
73 |
74 | // STRING
75 | if let value_str = obj as? String {
76 | try self.pack(string: value_str)
77 | }
78 |
79 | // UNSIGNED INT
80 | else if let value_u8 = obj as? UInt8 { // 8 BIT
81 | //try self.pack(signedInt: Int(value_u8))
82 | try self.pack(unsignedInt: UInt64(value_u8))
83 | }
84 | else if let value_u16 = obj as? UInt16 { // 16 BIT
85 | //try self.pack(signedInt: Int(value_u16))
86 | try self.pack(unsignedInt: UInt64(value_u16))
87 | }
88 | else if let value_u32 = obj as? UInt32 { // 32 BIT
89 | //try self.pack(signedInt: Int(value_u32))
90 | try self.pack(unsignedInt: UInt64(value_u32))
91 | }
92 | else if let value_u64 = obj as? UInt64 { // 64 BIT
93 | //try self.pack(unsignedInt: UInt(value_u64))
94 | try self.pack(unsignedInt: value_u64)
95 | }
96 |
97 |
98 | // SIGNED INT
99 | else if let value_i8 = obj as? Int8 { // 8 BIT
100 | try self.pack(signedInt: Int(value_i8))
101 | }
102 | else if let value_i16 = obj as? Int16 { // 16 BIT
103 | try self.pack(signedInt: Int(value_i16))
104 | }
105 | else if let value_i32 = obj as? Int32 { // 32 BIT
106 | try self.pack(signedInt: Int(value_i32))
107 | }
108 | else if let value_i64 = obj as? Int64 { // 64 BIT
109 | try self.pack(signedInt: Int(value_i64))
110 | }
111 |
112 |
113 | // DOUBLE
114 | else if let value_double = obj as? Double {
115 | try self.pack(double: value_double)
116 | }
117 | // FLOAT
118 | else if let value_float = obj as? Float {
119 | try self.pack(float: value_float)
120 | }
121 | // INT
122 | else if let value_int = obj as? Int {
123 | try self.pack(signedInt: value_int)
124 | }
125 | // UNSIGNED INT
126 | else if let value_uint = obj as? UInt {
127 | //try self.pack(unsignedInt: value_uint)
128 | try self.pack(unsignedInt: UInt64(value_uint))
129 | }
130 |
131 |
132 | // CHARACTER
133 | else if let value_char = obj as? Character {
134 | try self.pack(string: String(value_char))
135 | }
136 | // BOOLEAN VALUES
137 | else if let value_bool = obj as? Bool {
138 | try self.pack(boolean: value_bool)
139 | }
140 |
141 | // ARRAY
142 | else if let value_array = obj as? [Any?] {
143 | try self.pack(array: value_array)
144 | }
145 | // DICTIONARIES
146 | else if let value_dict = obj as? [AnyHashable: Any] {
147 | try self.pack(dict: value_dict)
148 | }
149 | // DICTIONARIES WITH OPTIONAL VALUES
150 | else if let value_dict = obj as? [AnyHashable: Any?] {
151 | try self.pack(dict: value_dict)
152 | }
153 | // DATA
154 | else if let value_data = obj as? Data {
155 | try self.pack(data: value_data)
156 | }
157 |
158 | // Not supported fallback
159 | else {
160 | throw MsgPackError.unsupportedValue(obj)
161 | }
162 | return self
163 | }
164 |
165 | // MARK: - Pack `string` value
166 |
167 | /// This function pack a String instance
168 | ///
169 | /// - Parameter value: string to pack
170 | /// - Returns: the instance of `self` modified with the packed data
171 | /// - Throws: throw if string cannot be encoded (`.invalidEncoding`) or data is too much
172 | /// to be packed in a MsgPack message (`.dataIsTooBig`)
173 | @discardableResult
174 | private mutating func pack(string value: String) throws -> Data {
175 | guard !value.isEmpty else { // String instance is empty
176 | // Fixed string length (fixstr 101xxxxx 0xa0 - 0xbf)
177 | try self.writeDataTypeHeader(.fixstr)
178 | return self
179 | }
180 | // Attempt to encode the String instance to a data by encoding it using UTF-8
181 | guard let encoded_data = value.data(using: String.Encoding.utf8) else {
182 | // Something went wrong and we can't continue packing data
183 | throw MsgPackError.invalidEncoding
184 | }
185 |
186 | // Write specific header for string
187 | let len = encoded_data.count
188 | try self.writeHeader(forString: len)
189 | // Write the contents of data
190 | self.writeData(encoded_data)
191 | return self
192 | }
193 |
194 | // MARK: - Pack `boolean` value
195 |
196 | /// Pack a boolean value.
197 | /// Bool format family stores false or true in 1 byte (0xc2 for false and 0xc3 for true).
198 | /// (Specs: https://github.com/msgpack/msgpack/blob/master/spec.md#formats-bool)
199 | ///
200 | /// - Parameter bool: boolean value to pack
201 | /// - Returns: the instance of `self` modified with the packed data
202 | @discardableResult
203 | mutating func pack(boolean bool: Bool) throws -> Data {
204 | try self.writeDataTypeHeader(.boolean(bool))
205 | return self
206 | }
207 |
208 | // MARK: - Pack UInt
209 |
210 | /// Pack an unsigned `int` value
211 | ///
212 | /// - Parameter value: value to pack
213 | /// - Returns: the instance of `self` modified with the packed data
214 | /// - Throws: throw an exception if value cannot be encoded because is too large to be contained in a MsgPack message
215 | @discardableResult
216 | private mutating func pack(unsignedInt value: UInt64) throws -> Data {
217 | switch value {
218 | case 0...127:
219 | try self.writeDataTypeHeader(.pFixInt8(value: Int(value)))
220 |
221 | case UInt64(UInt8.min)...UInt64(UInt8.max):
222 | try self.writeDataTypeHeader(.uInt8)
223 |
224 | var data = UInt8(value)
225 | self.append(UnsafeBufferPointer(start: &data, count: 1))
226 |
227 | case UInt64(UInt16.min)...UInt64(UInt16.max):
228 | try self.writeDataTypeHeader(.uInt16)
229 |
230 | var data = UInt16(value).bigEndian
231 | self.append(UnsafeBufferPointer(start: &data, count: 1))
232 |
233 | case UInt64(UInt32.min)...UInt64(UInt32.max):
234 | try self.writeDataTypeHeader(.uInt32)
235 |
236 | var data = UInt32(value).bigEndian
237 | self.append(UnsafeBufferPointer(start: &data, count: 1))
238 |
239 | default:
240 | try self.writeDataTypeHeader(.uInt64)
241 | // Write value
242 | var data = UInt64(value).bigEndian
243 | self.append(UnsafeBufferPointer(start: &data, count: 1))
244 | }
245 |
246 | return self
247 | }
248 |
249 | // MARK: - Pack Int
250 |
251 | /// Pack a signed `int` value
252 | ///
253 | /// - Parameter value: value to encode
254 | /// - Returns: the instance of `self` modified with the packed data
255 | /// - Throws: throw an exception is value is too large to be encoded in a MsgPack message
256 | @discardableResult
257 | private mutating func pack(signedInt value: Int) throws -> Data {
258 | switch value {
259 | // POSITIVE INT 32 BIT
260 | case (Int(UInt16.max) + 1)...Int(Int32.max):
261 | try self.writeDataTypeHeader(.int32)
262 |
263 | var data = UInt32(value).bigEndian
264 | self.append(UnsafeBufferPointer(start: &data, count: 1))
265 |
266 | // UNSIGNED INT 16 BIT
267 | case (Int(Int16.max) + 1)...Int(UInt16.max):
268 | try self.writeDataTypeHeader(.uInt16)
269 |
270 | var data = UInt16(value).bigEndian
271 | self.append(UnsafeBufferPointer(start: &data, count: 1))
272 |
273 | // POSITIVE INT 16 BIT
274 | case (Int(UInt8.max) + 1)...Int(Int16.max):
275 | try self.writeDataTypeHeader(.int16)
276 |
277 | var data = UInt16(value).bigEndian
278 | self.append(UnsafeBufferPointer(start: &data, count: 1))
279 |
280 | // UNSIGNED INT 8 BIT
281 | case (Int(Int8.max) + 1)...Int(UInt8.max):
282 | try self.writeDataTypeHeader(.uInt8)
283 |
284 | var data = UInt8(value)
285 | self.append(UnsafeBufferPointer(start: &data, count: 1))
286 |
287 | // POSITIVE INT 8 BIT
288 | case 0...Int(Int8.max):
289 | try self.writeDataTypeHeader(.pFixInt8(value: value))
290 |
291 | // NEGATIVE FIX INT
292 | case -32..<0:
293 | try self.writeDataTypeHeader(.nFixInt(value: value))
294 |
295 | // NEGATIVE INT 8 BIT
296 | case Int(Int8.min)...(-33):
297 | try self.writeDataTypeHeader(.nInt8)
298 |
299 | var data = UInt8(value & 0xff)
300 | self.append(UnsafeBufferPointer(start: &data, count: 1))
301 |
302 | // NEGATIVE INT 16 BIT
303 | case Int(Int16.min)...(Int(Int8.min) - 1):
304 | try self.writeDataTypeHeader(.nInt16)
305 |
306 | var data = UInt16(bitPattern: Int16(value)).bigEndian
307 | self.append(UnsafeBufferPointer(start: &data, count: 1))
308 |
309 | // NEGATIVE INT 32 BIT
310 | case Int(Int32.min)...(Int(Int16.min) - 1):
311 | try self.writeDataTypeHeader(.nInt32)
312 |
313 | var data = UInt32(bitPattern: Int32(value)).bigEndian
314 | self.append(UnsafeBufferPointer(start: &data, count: 1))
315 |
316 | // INT 64 BIT
317 | default:
318 | try self.writeDataTypeHeader(.int64)
319 |
320 | var data = UInt64(bitPattern: Int64(value)).bigEndian
321 | self.append(UnsafeBufferPointer(start: &data, count: 1))
322 | }
323 |
324 | return self
325 | }
326 |
327 | // MARK: - Pack Float
328 |
329 | /// Pack a `float` value
330 | ///
331 | /// - Parameter value: `float` value to pack
332 | /// - Returns: the instance of `self` modified with the packed data
333 | @discardableResult
334 | private mutating func pack(float value: Float) throws -> Data {
335 | try self.writeDataTypeHeader(.float)
336 |
337 | var data = value.bitPattern.bigEndian
338 | self.append(UnsafeBufferPointer(start: &data, count: 1))
339 | return self
340 | }
341 |
342 | // MARK: - Pack Double
343 |
344 | /// Pack a `double` value
345 | ///
346 | /// - Parameter value: `double` value to pack
347 | /// - Returns: the instance of `self` modified with the packed data
348 | @discardableResult
349 | private mutating func pack(double value: Double) throws -> Data {
350 | try self.writeDataTypeHeader(.double)
351 |
352 | var data = value.bitPattern.bigEndian
353 | self.append(UnsafeBufferPointer(start: &data, count: 1))
354 | return self
355 | }
356 |
357 | // MARK: - Pack Data
358 |
359 | /// Pack `Data` instance
360 | ///
361 | /// - Parameter value: value to pack
362 | /// - Returns: the instance of `self` modified with the packed data
363 | /// - Throws: throw an exception if data is too large to be contained in a MsgPack data
364 | @discardableResult
365 | private mutating func pack(data value: Data) throws -> Data {
366 | // Write data prefix based upon the length
367 | try self.writeHeader(forData: value.count)
368 | // Append the data itself
369 | self.writeData(value)
370 | return self
371 | }
372 |
373 | // MARK: - Pack Array
374 |
375 | /// Pack an `array` of `Any?` instances
376 | ///
377 | /// - Parameter value: array to pack
378 | /// - Returns: the instance of `self` modified with the packed data
379 | /// - Throws: throw an exception if data is too large to be contained in a MsgPack data
380 | @discardableResult
381 | private mutating func pack(array value: [Any?]) throws -> Data {
382 |
383 | guard UInt32(bitPattern: Int32(value.count)) < UInt32.max else {
384 | //guard value.count < Int(UInt32.max) else {
385 | // Array is too large to be included in a MsgPack data
386 | throw MsgPackError.dataIsTooBig("Array is too big: \(value.count) items")
387 | }
388 |
389 | // Write the header of the array
390 | try self.writeHeader(forArray: value.count)
391 | // Let's encode each data contained in it
392 | try value.forEach {
393 | try self.pack($0)
394 | }
395 | return self
396 | }
397 |
398 | // MARK: - Pack Dictionary
399 |
400 | /// Pack `dictionary` with `AnyHashable` as key and `Any?` as value
401 | ///
402 | /// - value: dictionary to pack
403 | /// - Returns: the instance of `self` modified with the packed data
404 | /// - Throws: throw an exception if data is too large to be contained in a MsgPack data
405 | @discardableResult
406 | private mutating func pack(dict value: [AnyHashable:Any?]) throws -> Data {
407 |
408 | guard UInt32(bitPattern: Int32(value.count)) < UInt32.max else {
409 | // guard value.count < Int(UInt32.max) else {
410 | // Dictionary is too large to be contained in a MsgPack data
411 | throw MsgPackError.dataIsTooBig("Dictionary is too big: \(value.count) items")
412 | }
413 |
414 | // Write the header for dictionary
415 | try self.writeHeader(forDictionary: value.count)
416 |
417 | // Let's encode each `{value,key}` inside
418 | for (k,v) in value {
419 | try self.pack(k)
420 | try self.pack(v)
421 | }
422 | return self
423 | }
424 |
425 | //MARK: - Helper Functions
426 |
427 |
428 | /// Write the header prefix for each data type
429 | ///
430 | /// - Parameter type: type to write
431 | private mutating func writeDataTypeHeader(_ type: MsgPackType) throws {
432 | var type_value = try type.value()
433 | self.append( UnsafeBufferPointer(start: &type_value, count: 1) )
434 | }
435 |
436 |
437 | /// Just a shortcut to append a`data` instance to `self`
438 | ///
439 | /// - Parameter data: data to add
440 | private mutating func writeData(_ data: Data) {
441 | self.append(data)
442 | }
443 |
444 |
445 | private mutating func writeHeader(forDictionary length: Int) throws {
446 | // Write header
447 | try self.writeDataTypeHeader(.dict(items: length))
448 |
449 | // Write length if necessary
450 | if length < 16 {
451 | } else if length < Int(UInt16.max) {
452 | var data_len = UInt16(length).bigEndian
453 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
454 | } else { //if length < Int(UInt32.max) {
455 | var data_len = UInt32(length).bigEndian
456 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
457 | }
458 | }
459 |
460 | /// Write header for 'Array' storage
461 | ///
462 | /// - Parameter length: number of items in array
463 | /// - Throws: throw an exception if data is too large
464 | private mutating func writeHeader(forArray length: Int) throws {
465 | // Write header
466 | try self.writeDataTypeHeader(.array(items: length))
467 |
468 | // Write length if necessary
469 | if length < 16 {
470 | } else if length < Int(UInt16.max) {
471 | var data_len = UInt16(length).bigEndian
472 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
473 | } else { //if length < Int(UInt32.max) {
474 | var data_len = UInt32(length).bigEndian
475 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
476 | }
477 |
478 | }
479 |
480 | /// Write prefix for `String` based upon the length of the string itself
481 | ///
482 | /// - Parameter length: length of the string you want to add
483 | /// - Throws: throw an exception if data is too large
484 | private mutating func writeHeader(forString length: Int) throws {
485 | try self.writeDataTypeHeader(.str(length: length))
486 | if length < 32 {
487 | // already written above
488 | }
489 | else if length < Int(UInt8.max) {
490 | var len_data = UInt8(length)
491 | self.append(UnsafeBufferPointer(start: &len_data, count: 1))
492 | }
493 | else if length < Int(UInt16.max) {
494 | var len_data = UInt16(length).bigEndian
495 | self.append(UnsafeBufferPointer(start: &len_data, count: 1))
496 | }
497 | else { //if length < Int(UInt32.max) {
498 | var len_data = UInt32(length).bigEndian
499 | self.append(UnsafeBufferPointer(start: &len_data, count: 1))
500 | }
501 | }
502 |
503 |
504 | /// Write prefix for `Data` based upon the length of the `data` itself
505 | ///
506 | /// - Parameter length: length of data instance you want to write
507 | /// - Throws: throw an exception if data is too large
508 | private mutating func writeHeader(forData length: Int) throws {
509 | // 8 BIT LENGTH
510 | if length < Int(UInt8.max) {
511 | try self.writeDataTypeHeader(.bin8)
512 |
513 | var data_len = UInt8(length)
514 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
515 | }
516 | // 16 BIT LENGTH
517 | else if length < Int(UInt16.max) {
518 | try self.writeDataTypeHeader(.bin16)
519 |
520 | var data_len = UInt16(length).bigEndian
521 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
522 | }
523 | // 32 BIT LENGTH
524 | else { // if length < Int(UInt32.max) {
525 | try self.writeDataTypeHeader(.bin32)
526 |
527 | var data_len = UInt32(length).bigEndian
528 | self.append(UnsafeBufferPointer(start: &data_len, count: 1))
529 | }
530 | }
531 | }
532 |
--------------------------------------------------------------------------------
/SwiftMsgPack.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = 'SwiftMsgPack'
3 | spec.version = '1.2.0'
4 | spec.summary = 'MsgPack Encoder/Decoder in pure Swift'
5 | spec.homepage = 'https://github.com/malcommac/SwiftMsgPack'
6 | spec.license = { :type => 'MIT', :file => 'LICENSE' }
7 | spec.author = { 'Daniele Margutti' => 'me@danielemargutti.com' }
8 | spec.social_media_url = 'http://twitter.com/danielemargutti'
9 | spec.source = { :git => 'https://github.com/malcommac/SwiftMsgPack.git', :tag => "#{spec.version}" }
10 | spec.source_files = 'Sources/**/*.swift'
11 | spec.ios.deployment_target = '8.0'
12 | spec.osx.deployment_target = '10.10'
13 | spec.tvos.deployment_target = '9.0'
14 | spec.watchos.deployment_target = '2.0'
15 | spec.requires_arc = true
16 | spec.module_name = 'SwiftMsgPack'
17 | end
18 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0825C1D71E630FBA00D0CC70 /* SwiftMsgPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0825C1CD1E630FBA00D0CC70 /* SwiftMsgPack.framework */; };
11 | 0825C1DE1E630FBA00D0CC70 /* SwiftMsgPack.h in Headers */ = {isa = PBXBuildFile; fileRef = 0825C1D01E630FBA00D0CC70 /* SwiftMsgPack.h */; settings = {ATTRIBUTES = (Public, ); }; };
12 | 0825C1EB1E630FEB00D0CC70 /* Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0825C1E81E630FEB00D0CC70 /* Decoder.swift */; };
13 | 0825C1EC1E630FEB00D0CC70 /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0825C1E91E630FEB00D0CC70 /* Encoder.swift */; };
14 | 0825C1ED1E630FEB00D0CC70 /* Commons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0825C1EA1E630FEB00D0CC70 /* Commons.swift */; };
15 | 08B92EF51E631C7000B4390A /* SwiftMsgPackTests_String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B92EF41E631C7000B4390A /* SwiftMsgPackTests_String.swift */; };
16 | 08B92EF71E631D2200B4390A /* SwiftMsgPackTests_BoolNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B92EF61E631D2200B4390A /* SwiftMsgPackTests_BoolNil.swift */; };
17 | 08B92EF91E63202F00B4390A /* SwiftMsgPackTests_Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B92EF81E63202F00B4390A /* SwiftMsgPackTests_Data.swift */; };
18 | 08B92EFB1E63287D00B4390A /* SwiftMsgPackTests_Numeric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B92EFA1E63287D00B4390A /* SwiftMsgPackTests_Numeric.swift */; };
19 | 08B92EFD1E6339F300B4390A /* SwiftMsgPackTests_Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B92EFC1E6339F300B4390A /* SwiftMsgPackTests_Array.swift */; };
20 | 08B92EFF1E6346E900B4390A /* SwiftMsgPackTests_Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B92EFE1E6346E900B4390A /* SwiftMsgPackTests_Dictionary.swift */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXContainerItemProxy section */
24 | 0825C1D81E630FBA00D0CC70 /* PBXContainerItemProxy */ = {
25 | isa = PBXContainerItemProxy;
26 | containerPortal = 0825C1C41E630FBA00D0CC70 /* Project object */;
27 | proxyType = 1;
28 | remoteGlobalIDString = 0825C1CC1E630FBA00D0CC70;
29 | remoteInfo = SwiftMsgPack;
30 | };
31 | /* End PBXContainerItemProxy section */
32 |
33 | /* Begin PBXFileReference section */
34 | 0825C1CD1E630FBA00D0CC70 /* SwiftMsgPack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftMsgPack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 0825C1D01E630FBA00D0CC70 /* SwiftMsgPack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftMsgPack.h; sourceTree = ""; };
36 | 0825C1D11E630FBA00D0CC70 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | 0825C1D61E630FBA00D0CC70 /* SwiftMsgPackTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMsgPackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
38 | 0825C1DD1E630FBA00D0CC70 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
39 | 0825C1E81E630FEB00D0CC70 /* Decoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Decoder.swift; path = ../Sources/SwiftMsgPack/Decoder.swift; sourceTree = ""; };
40 | 0825C1E91E630FEB00D0CC70 /* Encoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Encoder.swift; path = ../Sources/SwiftMsgPack/Encoder.swift; sourceTree = ""; };
41 | 0825C1EA1E630FEB00D0CC70 /* Commons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Commons.swift; path = ../Sources/SwiftMsgPack/Commons.swift; sourceTree = ""; };
42 | 08B92EF41E631C7000B4390A /* SwiftMsgPackTests_String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftMsgPackTests_String.swift; path = ../../Tests/SwiftMsgPackTests/SwiftMsgPackTests_String.swift; sourceTree = ""; };
43 | 08B92EF61E631D2200B4390A /* SwiftMsgPackTests_BoolNil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftMsgPackTests_BoolNil.swift; path = ../../Tests/SwiftMsgPackTests/SwiftMsgPackTests_BoolNil.swift; sourceTree = ""; };
44 | 08B92EF81E63202F00B4390A /* SwiftMsgPackTests_Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftMsgPackTests_Data.swift; path = ../../Tests/SwiftMsgPackTests/SwiftMsgPackTests_Data.swift; sourceTree = ""; };
45 | 08B92EFA1E63287D00B4390A /* SwiftMsgPackTests_Numeric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftMsgPackTests_Numeric.swift; path = ../../Tests/SwiftMsgPackTests/SwiftMsgPackTests_Numeric.swift; sourceTree = ""; };
46 | 08B92EFC1E6339F300B4390A /* SwiftMsgPackTests_Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftMsgPackTests_Array.swift; path = ../../Tests/SwiftMsgPackTests/SwiftMsgPackTests_Array.swift; sourceTree = ""; };
47 | 08B92EFE1E6346E900B4390A /* SwiftMsgPackTests_Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftMsgPackTests_Dictionary.swift; path = ../../Tests/SwiftMsgPackTests/SwiftMsgPackTests_Dictionary.swift; sourceTree = ""; };
48 | /* End PBXFileReference section */
49 |
50 | /* Begin PBXFrameworksBuildPhase section */
51 | 0825C1C91E630FBA00D0CC70 /* Frameworks */ = {
52 | isa = PBXFrameworksBuildPhase;
53 | buildActionMask = 2147483647;
54 | files = (
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | 0825C1D31E630FBA00D0CC70 /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 0825C1D71E630FBA00D0CC70 /* SwiftMsgPack.framework in Frameworks */,
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXFrameworksBuildPhase section */
67 |
68 | /* Begin PBXGroup section */
69 | 0825C1C31E630FBA00D0CC70 = {
70 | isa = PBXGroup;
71 | children = (
72 | 0825C1E71E630FDB00D0CC70 /* SwiftMsgPack Library */,
73 | 0825C1CF1E630FBA00D0CC70 /* SwiftMsgPack */,
74 | 0825C1DA1E630FBA00D0CC70 /* SwiftMsgPackTests */,
75 | 0825C1CE1E630FBA00D0CC70 /* Products */,
76 | );
77 | sourceTree = "";
78 | };
79 | 0825C1CE1E630FBA00D0CC70 /* Products */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 0825C1CD1E630FBA00D0CC70 /* SwiftMsgPack.framework */,
83 | 0825C1D61E630FBA00D0CC70 /* SwiftMsgPackTests.xctest */,
84 | );
85 | name = Products;
86 | sourceTree = "";
87 | };
88 | 0825C1CF1E630FBA00D0CC70 /* SwiftMsgPack */ = {
89 | isa = PBXGroup;
90 | children = (
91 | 0825C1D01E630FBA00D0CC70 /* SwiftMsgPack.h */,
92 | 0825C1D11E630FBA00D0CC70 /* Info.plist */,
93 | );
94 | path = SwiftMsgPack;
95 | sourceTree = "";
96 | };
97 | 0825C1DA1E630FBA00D0CC70 /* SwiftMsgPackTests */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 08B92EF41E631C7000B4390A /* SwiftMsgPackTests_String.swift */,
101 | 08B92EF81E63202F00B4390A /* SwiftMsgPackTests_Data.swift */,
102 | 08B92EF61E631D2200B4390A /* SwiftMsgPackTests_BoolNil.swift */,
103 | 08B92EFA1E63287D00B4390A /* SwiftMsgPackTests_Numeric.swift */,
104 | 08B92EFC1E6339F300B4390A /* SwiftMsgPackTests_Array.swift */,
105 | 08B92EFE1E6346E900B4390A /* SwiftMsgPackTests_Dictionary.swift */,
106 | 0825C1DD1E630FBA00D0CC70 /* Info.plist */,
107 | );
108 | path = SwiftMsgPackTests;
109 | sourceTree = "";
110 | };
111 | 0825C1E71E630FDB00D0CC70 /* SwiftMsgPack Library */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 0825C1EA1E630FEB00D0CC70 /* Commons.swift */,
115 | 0825C1E91E630FEB00D0CC70 /* Encoder.swift */,
116 | 0825C1E81E630FEB00D0CC70 /* Decoder.swift */,
117 | );
118 | name = "SwiftMsgPack Library";
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXHeadersBuildPhase section */
124 | 0825C1CA1E630FBA00D0CC70 /* Headers */ = {
125 | isa = PBXHeadersBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | 0825C1DE1E630FBA00D0CC70 /* SwiftMsgPack.h in Headers */,
129 | );
130 | runOnlyForDeploymentPostprocessing = 0;
131 | };
132 | /* End PBXHeadersBuildPhase section */
133 |
134 | /* Begin PBXNativeTarget section */
135 | 0825C1CC1E630FBA00D0CC70 /* SwiftMsgPack */ = {
136 | isa = PBXNativeTarget;
137 | buildConfigurationList = 0825C1E11E630FBA00D0CC70 /* Build configuration list for PBXNativeTarget "SwiftMsgPack" */;
138 | buildPhases = (
139 | 0825C1C81E630FBA00D0CC70 /* Sources */,
140 | 0825C1C91E630FBA00D0CC70 /* Frameworks */,
141 | 0825C1CA1E630FBA00D0CC70 /* Headers */,
142 | 0825C1CB1E630FBA00D0CC70 /* Resources */,
143 | );
144 | buildRules = (
145 | );
146 | dependencies = (
147 | );
148 | name = SwiftMsgPack;
149 | productName = SwiftMsgPack;
150 | productReference = 0825C1CD1E630FBA00D0CC70 /* SwiftMsgPack.framework */;
151 | productType = "com.apple.product-type.framework";
152 | };
153 | 0825C1D51E630FBA00D0CC70 /* SwiftMsgPackTests */ = {
154 | isa = PBXNativeTarget;
155 | buildConfigurationList = 0825C1E41E630FBA00D0CC70 /* Build configuration list for PBXNativeTarget "SwiftMsgPackTests" */;
156 | buildPhases = (
157 | 0825C1D21E630FBA00D0CC70 /* Sources */,
158 | 0825C1D31E630FBA00D0CC70 /* Frameworks */,
159 | 0825C1D41E630FBA00D0CC70 /* Resources */,
160 | );
161 | buildRules = (
162 | );
163 | dependencies = (
164 | 0825C1D91E630FBA00D0CC70 /* PBXTargetDependency */,
165 | );
166 | name = SwiftMsgPackTests;
167 | productName = SwiftMsgPackTests;
168 | productReference = 0825C1D61E630FBA00D0CC70 /* SwiftMsgPackTests.xctest */;
169 | productType = "com.apple.product-type.bundle.unit-test";
170 | };
171 | /* End PBXNativeTarget section */
172 |
173 | /* Begin PBXProject section */
174 | 0825C1C41E630FBA00D0CC70 /* Project object */ = {
175 | isa = PBXProject;
176 | attributes = {
177 | LastSwiftUpdateCheck = 0820;
178 | LastUpgradeCheck = 0820;
179 | ORGANIZATIONNAME = moka;
180 | TargetAttributes = {
181 | 0825C1CC1E630FBA00D0CC70 = {
182 | CreatedOnToolsVersion = 8.2.1;
183 | DevelopmentTeam = E5DU3FA699;
184 | LastSwiftMigration = 0820;
185 | ProvisioningStyle = Automatic;
186 | };
187 | 0825C1D51E630FBA00D0CC70 = {
188 | CreatedOnToolsVersion = 8.2.1;
189 | DevelopmentTeam = E5DU3FA699;
190 | LastSwiftMigration = 0820;
191 | ProvisioningStyle = Automatic;
192 | };
193 | };
194 | };
195 | buildConfigurationList = 0825C1C71E630FBA00D0CC70 /* Build configuration list for PBXProject "SwiftMsgPack" */;
196 | compatibilityVersion = "Xcode 3.2";
197 | developmentRegion = English;
198 | hasScannedForEncodings = 0;
199 | knownRegions = (
200 | en,
201 | );
202 | mainGroup = 0825C1C31E630FBA00D0CC70;
203 | productRefGroup = 0825C1CE1E630FBA00D0CC70 /* Products */;
204 | projectDirPath = "";
205 | projectRoot = "";
206 | targets = (
207 | 0825C1CC1E630FBA00D0CC70 /* SwiftMsgPack */,
208 | 0825C1D51E630FBA00D0CC70 /* SwiftMsgPackTests */,
209 | );
210 | };
211 | /* End PBXProject section */
212 |
213 | /* Begin PBXResourcesBuildPhase section */
214 | 0825C1CB1E630FBA00D0CC70 /* Resources */ = {
215 | isa = PBXResourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | );
219 | runOnlyForDeploymentPostprocessing = 0;
220 | };
221 | 0825C1D41E630FBA00D0CC70 /* Resources */ = {
222 | isa = PBXResourcesBuildPhase;
223 | buildActionMask = 2147483647;
224 | files = (
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | };
228 | /* End PBXResourcesBuildPhase section */
229 |
230 | /* Begin PBXSourcesBuildPhase section */
231 | 0825C1C81E630FBA00D0CC70 /* Sources */ = {
232 | isa = PBXSourcesBuildPhase;
233 | buildActionMask = 2147483647;
234 | files = (
235 | 0825C1EB1E630FEB00D0CC70 /* Decoder.swift in Sources */,
236 | 0825C1EC1E630FEB00D0CC70 /* Encoder.swift in Sources */,
237 | 0825C1ED1E630FEB00D0CC70 /* Commons.swift in Sources */,
238 | );
239 | runOnlyForDeploymentPostprocessing = 0;
240 | };
241 | 0825C1D21E630FBA00D0CC70 /* Sources */ = {
242 | isa = PBXSourcesBuildPhase;
243 | buildActionMask = 2147483647;
244 | files = (
245 | 08B92EF91E63202F00B4390A /* SwiftMsgPackTests_Data.swift in Sources */,
246 | 08B92EF71E631D2200B4390A /* SwiftMsgPackTests_BoolNil.swift in Sources */,
247 | 08B92EFF1E6346E900B4390A /* SwiftMsgPackTests_Dictionary.swift in Sources */,
248 | 08B92EFB1E63287D00B4390A /* SwiftMsgPackTests_Numeric.swift in Sources */,
249 | 08B92EFD1E6339F300B4390A /* SwiftMsgPackTests_Array.swift in Sources */,
250 | 08B92EF51E631C7000B4390A /* SwiftMsgPackTests_String.swift in Sources */,
251 | );
252 | runOnlyForDeploymentPostprocessing = 0;
253 | };
254 | /* End PBXSourcesBuildPhase section */
255 |
256 | /* Begin PBXTargetDependency section */
257 | 0825C1D91E630FBA00D0CC70 /* PBXTargetDependency */ = {
258 | isa = PBXTargetDependency;
259 | target = 0825C1CC1E630FBA00D0CC70 /* SwiftMsgPack */;
260 | targetProxy = 0825C1D81E630FBA00D0CC70 /* PBXContainerItemProxy */;
261 | };
262 | /* End PBXTargetDependency section */
263 |
264 | /* Begin XCBuildConfiguration section */
265 | 0825C1DF1E630FBA00D0CC70 /* Debug */ = {
266 | isa = XCBuildConfiguration;
267 | buildSettings = {
268 | ALWAYS_SEARCH_USER_PATHS = NO;
269 | CLANG_ANALYZER_NONNULL = YES;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BOOL_CONVERSION = YES;
275 | CLANG_WARN_CONSTANT_CONVERSION = YES;
276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
277 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
278 | CLANG_WARN_EMPTY_BODY = YES;
279 | CLANG_WARN_ENUM_CONVERSION = YES;
280 | CLANG_WARN_INFINITE_RECURSION = YES;
281 | CLANG_WARN_INT_CONVERSION = YES;
282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
283 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
284 | CLANG_WARN_UNREACHABLE_CODE = YES;
285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
286 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
287 | COPY_PHASE_STRIP = NO;
288 | CURRENT_PROJECT_VERSION = 1;
289 | DEBUG_INFORMATION_FORMAT = dwarf;
290 | ENABLE_STRICT_OBJC_MSGSEND = YES;
291 | ENABLE_TESTABILITY = YES;
292 | GCC_C_LANGUAGE_STANDARD = gnu99;
293 | GCC_DYNAMIC_NO_PIC = NO;
294 | GCC_NO_COMMON_BLOCKS = YES;
295 | GCC_OPTIMIZATION_LEVEL = 0;
296 | GCC_PREPROCESSOR_DEFINITIONS = (
297 | "DEBUG=1",
298 | "$(inherited)",
299 | );
300 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
301 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
302 | GCC_WARN_UNDECLARED_SELECTOR = YES;
303 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
304 | GCC_WARN_UNUSED_FUNCTION = YES;
305 | GCC_WARN_UNUSED_VARIABLE = YES;
306 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
307 | MTL_ENABLE_DEBUG_INFO = YES;
308 | ONLY_ACTIVE_ARCH = YES;
309 | SDKROOT = iphoneos;
310 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
311 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
312 | SWIFT_VERSION = 4.0;
313 | TARGETED_DEVICE_FAMILY = "1,2,3,4";
314 | VERSIONING_SYSTEM = "apple-generic";
315 | VERSION_INFO_PREFIX = "";
316 | };
317 | name = Debug;
318 | };
319 | 0825C1E01E630FBA00D0CC70 /* Release */ = {
320 | isa = XCBuildConfiguration;
321 | buildSettings = {
322 | ALWAYS_SEARCH_USER_PATHS = NO;
323 | CLANG_ANALYZER_NONNULL = YES;
324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
325 | CLANG_CXX_LIBRARY = "libc++";
326 | CLANG_ENABLE_MODULES = YES;
327 | CLANG_ENABLE_OBJC_ARC = YES;
328 | CLANG_WARN_BOOL_CONVERSION = YES;
329 | CLANG_WARN_CONSTANT_CONVERSION = YES;
330 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
331 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
332 | CLANG_WARN_EMPTY_BODY = YES;
333 | CLANG_WARN_ENUM_CONVERSION = YES;
334 | CLANG_WARN_INFINITE_RECURSION = YES;
335 | CLANG_WARN_INT_CONVERSION = YES;
336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
337 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
338 | CLANG_WARN_UNREACHABLE_CODE = YES;
339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
341 | COPY_PHASE_STRIP = NO;
342 | CURRENT_PROJECT_VERSION = 1;
343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
344 | ENABLE_NS_ASSERTIONS = NO;
345 | ENABLE_STRICT_OBJC_MSGSEND = YES;
346 | GCC_C_LANGUAGE_STANDARD = gnu99;
347 | GCC_NO_COMMON_BLOCKS = YES;
348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
350 | GCC_WARN_UNDECLARED_SELECTOR = YES;
351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
352 | GCC_WARN_UNUSED_FUNCTION = YES;
353 | GCC_WARN_UNUSED_VARIABLE = YES;
354 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
355 | MTL_ENABLE_DEBUG_INFO = NO;
356 | SDKROOT = iphoneos;
357 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
358 | SWIFT_VERSION = 4.0;
359 | TARGETED_DEVICE_FAMILY = "1,2,3,4";
360 | VALIDATE_PRODUCT = YES;
361 | VERSIONING_SYSTEM = "apple-generic";
362 | VERSION_INFO_PREFIX = "";
363 | };
364 | name = Release;
365 | };
366 | 0825C1E21E630FBA00D0CC70 /* Debug */ = {
367 | isa = XCBuildConfiguration;
368 | buildSettings = {
369 | ARCHS = "$(ARCHS_STANDARD)";
370 | CLANG_ENABLE_MODULES = YES;
371 | CODE_SIGN_IDENTITY = "";
372 | DEFINES_MODULE = YES;
373 | DEVELOPMENT_TEAM = E5DU3FA699;
374 | DYLIB_COMPATIBILITY_VERSION = 1;
375 | DYLIB_CURRENT_VERSION = 1;
376 | DYLIB_INSTALL_NAME_BASE = "@rpath";
377 | INFOPLIST_FILE = SwiftMsgPack/Info.plist;
378 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
379 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
381 | MACOSX_DEPLOYMENT_TARGET = 10.10;
382 | PRODUCT_BUNDLE_IDENTIFIER = com.mokasw.SwiftMsgPack;
383 | PRODUCT_NAME = "$(TARGET_NAME)";
384 | SKIP_INSTALL = YES;
385 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos";
386 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
387 | SWIFT_VERSION = 4.0;
388 | TVOS_DEPLOYMENT_TARGET = 9.0;
389 | };
390 | name = Debug;
391 | };
392 | 0825C1E31E630FBA00D0CC70 /* Release */ = {
393 | isa = XCBuildConfiguration;
394 | buildSettings = {
395 | ARCHS = "$(ARCHS_STANDARD)";
396 | CLANG_ENABLE_MODULES = YES;
397 | CODE_SIGN_IDENTITY = "";
398 | DEFINES_MODULE = YES;
399 | DEVELOPMENT_TEAM = E5DU3FA699;
400 | DYLIB_COMPATIBILITY_VERSION = 1;
401 | DYLIB_CURRENT_VERSION = 1;
402 | DYLIB_INSTALL_NAME_BASE = "@rpath";
403 | INFOPLIST_FILE = SwiftMsgPack/Info.plist;
404 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
405 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
406 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
407 | MACOSX_DEPLOYMENT_TARGET = 10.10;
408 | PRODUCT_BUNDLE_IDENTIFIER = com.mokasw.SwiftMsgPack;
409 | PRODUCT_NAME = "$(TARGET_NAME)";
410 | SKIP_INSTALL = YES;
411 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos";
412 | SWIFT_VERSION = 4.0;
413 | TVOS_DEPLOYMENT_TARGET = 9.0;
414 | };
415 | name = Release;
416 | };
417 | 0825C1E51E630FBA00D0CC70 /* Debug */ = {
418 | isa = XCBuildConfiguration;
419 | buildSettings = {
420 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
421 | CLANG_ENABLE_MODULES = YES;
422 | DEVELOPMENT_TEAM = E5DU3FA699;
423 | INFOPLIST_FILE = SwiftMsgPackTests/Info.plist;
424 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
425 | PRODUCT_BUNDLE_IDENTIFIER = com.mokasw.SwiftMsgPackTests;
426 | PRODUCT_NAME = "$(TARGET_NAME)";
427 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
428 | SWIFT_VERSION = 4.0;
429 | };
430 | name = Debug;
431 | };
432 | 0825C1E61E630FBA00D0CC70 /* Release */ = {
433 | isa = XCBuildConfiguration;
434 | buildSettings = {
435 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
436 | CLANG_ENABLE_MODULES = YES;
437 | DEVELOPMENT_TEAM = E5DU3FA699;
438 | INFOPLIST_FILE = SwiftMsgPackTests/Info.plist;
439 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
440 | PRODUCT_BUNDLE_IDENTIFIER = com.mokasw.SwiftMsgPackTests;
441 | PRODUCT_NAME = "$(TARGET_NAME)";
442 | SWIFT_VERSION = 4.0;
443 | };
444 | name = Release;
445 | };
446 | /* End XCBuildConfiguration section */
447 |
448 | /* Begin XCConfigurationList section */
449 | 0825C1C71E630FBA00D0CC70 /* Build configuration list for PBXProject "SwiftMsgPack" */ = {
450 | isa = XCConfigurationList;
451 | buildConfigurations = (
452 | 0825C1DF1E630FBA00D0CC70 /* Debug */,
453 | 0825C1E01E630FBA00D0CC70 /* Release */,
454 | );
455 | defaultConfigurationIsVisible = 0;
456 | defaultConfigurationName = Release;
457 | };
458 | 0825C1E11E630FBA00D0CC70 /* Build configuration list for PBXNativeTarget "SwiftMsgPack" */ = {
459 | isa = XCConfigurationList;
460 | buildConfigurations = (
461 | 0825C1E21E630FBA00D0CC70 /* Debug */,
462 | 0825C1E31E630FBA00D0CC70 /* Release */,
463 | );
464 | defaultConfigurationIsVisible = 0;
465 | defaultConfigurationName = Release;
466 | };
467 | 0825C1E41E630FBA00D0CC70 /* Build configuration list for PBXNativeTarget "SwiftMsgPackTests" */ = {
468 | isa = XCConfigurationList;
469 | buildConfigurations = (
470 | 0825C1E51E630FBA00D0CC70 /* Debug */,
471 | 0825C1E61E630FBA00D0CC70 /* Release */,
472 | );
473 | defaultConfigurationIsVisible = 0;
474 | defaultConfigurationName = Release;
475 | };
476 | /* End XCConfigurationList section */
477 | };
478 | rootObject = 0825C1C41E630FBA00D0CC70 /* Project object */;
479 | }
480 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/project.xcworkspace/xcuserdata/dan.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/SwiftMsgPack/6a9b7d73f78cd0f7e5ad280fde39a347f15baaf7/SwiftMsgPack/SwiftMsgPack.xcodeproj/project.xcworkspace/xcuserdata/dan.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/project.xcworkspace/xcuserdata/danielemm.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/SwiftMsgPack/6a9b7d73f78cd0f7e5ad280fde39a347f15baaf7/SwiftMsgPack/SwiftMsgPack.xcodeproj/project.xcworkspace/xcuserdata/danielemm.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/xcshareddata/xcschemes/SwiftMsgPack.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/xcuserdata/danielemm.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
24 |
36 |
37 |
38 |
40 |
52 |
53 |
54 |
56 |
68 |
69 |
70 |
72 |
84 |
85 |
86 |
88 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack.xcodeproj/xcuserdata/danielemm.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwiftMsgPack.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 0825C1CC1E630FBA00D0CC70
16 |
17 | primary
18 |
19 |
20 | 0825C1D51E630FBA00D0CC70
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.9
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPack/SwiftMsgPack.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftMsgPack.h
3 | // SwiftMsgPack
4 | //
5 | // Created by Daniele Margutti on 26/02/2017.
6 | // Copyright © 2017 moka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SwiftMsgPack.
12 | FOUNDATION_EXPORT double SwiftMsgPackVersionNumber;
13 |
14 | //! Project version string for SwiftMsgPack.
15 | FOUNDATION_EXPORT const unsigned char SwiftMsgPackVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SwiftMsgPack/SwiftMsgPackTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/SwiftMsgPack/6a9b7d73f78cd0f7e5ad280fde39a347f15baaf7/Tests/.DS_Store
--------------------------------------------------------------------------------
/Tests/SwiftMsgPackTests/SwiftMsgPackTests_Array.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 |
34 | import XCTest
35 | @testable import SwiftMsgPack
36 |
37 | class SwiftMsgPackTests_Array: XCTestCase {
38 |
39 | override func setUp() {
40 | super.setUp()
41 | }
42 |
43 | override func tearDown() {
44 | super.tearDown()
45 | }
46 |
47 | // MARK: - Test on Array type
48 |
49 |
50 | /// Test small array
51 | func testSmallArray() {
52 | let len = 15
53 | let (array,exp) = generateTestArray(len)
54 | performTestOnArray(name: "Test Small Array", value: array, expected: exp)
55 | }
56 |
57 | /// Test medium array
58 | func testMediumArray() {
59 | let len = UInt16(UInt16.max - 1)
60 | let (array,exp) = generateTestArray(Int(len))
61 | performTestOnArray(name: "Test Medium Array", value: array, expected: exp)
62 | }
63 |
64 | /// Test long array
65 | func testLongArray() {
66 | let len = UInt32(UInt16.max) + 1
67 | let (array,exp) = generateTestArray(Int(len))
68 | performTestOnArray(name: "Test Long Array", value: array, expected: exp)
69 | }
70 |
71 | // MARK: Helper Functions
72 |
73 | /// Generate a Test array and return both it and expected bytes for its packed version
74 | ///
75 | /// - Parameter count: number of items in array
76 | /// - Returns: array and expected bytes
77 | func generateTestArray(_ count: Int) -> ([Any?],[UInt8]) {
78 | var array: [Any?] = []
79 | var bytes: [UInt8] = []
80 |
81 | // Generate Header for Array
82 | if count < 16 {
83 | // Header + Length
84 | bytes.append(UInt8(0x90 + count))
85 | }
86 | else if count < Int(UInt16.max) {
87 | // Header
88 | bytes.append(UInt8(0xdc))
89 | // Length (big endian)
90 | bytes.append(UInt8((count >> 8) & 0xff))
91 | bytes.append(UInt8(count & 0xff))
92 | }
93 | else if count < Int(UInt32.max) {
94 | // Header
95 | bytes.append(UInt8(0xdd))
96 | // Length (big endian)
97 | bytes.append(UInt8((count >> 24) & 0xff))
98 | bytes.append(UInt8((count >> 16) & 0xff))
99 | bytes.append(UInt8((count >> 8) & 0xff))
100 | bytes.append(UInt8(count & 0xff))
101 | }
102 |
103 | // Append items to array
104 | for _ in 0.. (Any?,[UInt8]) {
120 | let type = randomValue(min: 0, max: 3)
121 | var item: Any?
122 | var bytes: [UInt8] = []
123 |
124 | // Just to test some types
125 | switch type {
126 | case 0: // nil
127 | item = nil
128 |
129 | let header: UInt8 = UInt8(0xc0)
130 | bytes.append(header)
131 | case 1: // Boolean
132 | let bool_val = randomValue(min: 0, max: 1)
133 | item = (bool_val == 0 ? false : true)
134 |
135 | let header: UInt8 = (item as! Bool == true ? UInt8(0xc3) : UInt8(0xc2))
136 | bytes.append(header)
137 | case 2: // Int
138 | let int8Num = randomValue(min: 0, max: Int(Int8.max))
139 | item = int8Num
140 |
141 | let header: UInt8 = UInt8(int8Num & 0x7f)
142 | bytes.append(header)
143 | case 3: // Fixed String
144 | let random_len = randomValue(min: 1, max: 20)
145 | let str = randomString(length: random_len)
146 | item = str
147 |
148 | let header: UInt8 = UInt8(UInt8(0xa0) + UInt8(random_len))
149 | bytes.append(header)
150 |
151 | let encoded_data = str.data(using: String.Encoding.utf8)!
152 | bytes.append(contentsOf: [UInt8](encoded_data))
153 | default:
154 | break
155 | }
156 |
157 | return (item,bytes)
158 | }
159 |
160 | /// Generate a random string with passed length
161 | ///
162 | /// - Parameter length: length of the string
163 | /// - Returns: random alphanumeric string
164 | func randomString(length: Int) -> String {
165 | let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
166 | let len = UInt32(letters.length)
167 | var randomString = ""
168 | for _ in 0 ..< length {
169 | let rand = arc4random_uniform(len)
170 | var nextChar = letters.character(at: Int(rand))
171 | randomString += NSString(characters: &nextChar, length: 1) as String
172 | }
173 | return randomString
174 | }
175 |
176 |
177 | /// Generate a random number in a range
178 | ///
179 | /// - Parameters:
180 | /// - min: min value
181 | /// - max: max value
182 | /// - Returns: random value
183 | func randomValue(min: Int, max: Int) -> Int {
184 | return Int(arc4random_uniform(UInt32(max) - UInt32(min)) + UInt32(min))
185 | }
186 |
187 | func performTestOnArray(name testName: String, value: [Any?], expected bytes: [UInt8]) {
188 | var packed = Data()
189 |
190 | do {
191 | try packed.pack(value)
192 |
193 | guard packed.count == bytes.count else {
194 | XCTFail("[\(testName)] Pack failed because number of bytes is different from expected: \(packed.count), \(bytes.count) expected")
195 | return
196 | }
197 |
198 | var idx = 0
199 | for byte in packed {
200 | guard byte == bytes[idx] else {
201 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
202 | return
203 | }
204 | idx += 1
205 | }
206 |
207 |
208 | } catch let err {
209 | // Something went wrong while packing data
210 | XCTFail("[\(testName)] Failed to pack Array: \(err) (src='\(value)')")
211 | return
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/Tests/SwiftMsgPackTests/SwiftMsgPackTests_BoolNil.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 | import Foundation
34 |
35 | import XCTest
36 | @testable import SwiftMsgPack
37 |
38 | class SwiftMsgPackTests_BoolNil: XCTestCase {
39 |
40 | override func setUp() {
41 | super.setUp()
42 | }
43 |
44 | override func tearDown() {
45 | super.tearDown()
46 | }
47 |
48 | // MARK: - Test `bool` type
49 |
50 | /// Test boolean `true` value
51 | func testBoolean_true() {
52 | performBooleanTest(name: "Test True", value: true, expected: UInt8(0xc3))
53 | }
54 |
55 | /// Test boolean `false` value
56 | func testBoolean_false() {
57 | performBooleanTest(name: "Test False", value: false, expected: UInt8(0xc2))
58 | }
59 |
60 | // MARK: - Test `nil` value type
61 |
62 | func testNil() {
63 | let data: Any? = nil
64 | performNilTest(name: "Nil Test", value: data, expected: UInt8(0xc0))
65 | }
66 |
67 | // MARK: Helper Functions
68 |
69 | func performNilTest(name testName: String, value: Any?, expected byte: UInt8) {
70 | var packed = Data()
71 | do {
72 | try packed.pack(value)
73 |
74 | guard packed.count == 1 else {
75 | XCTFail("[\(testName)] Nil pack should contains only 1 byte (\(packed.count) bytes found)")
76 | return
77 | }
78 |
79 | guard packed[0] == byte else {
80 | XCTFail("[\(testName)] Nil pack is different from expected")
81 | return
82 | }
83 |
84 | if let _ = try packed.unpack() {
85 | XCTFail("[\(testName)] A value is found while unpacking a nil value")
86 | return
87 | }
88 |
89 | } catch let err {
90 | // Something went wrong while packing data
91 | XCTFail("[\(testName)] Failed to pack nil: \(err) (src='\(String(describing: value))')")
92 | return
93 | }
94 | }
95 |
96 | func performBooleanTest(name testName: String, value: Bool, expected byte: UInt8) {
97 | var packed = Data()
98 | do {
99 | // Pack data
100 | try packed.pack(value)
101 |
102 | guard packed.count == 1 else {
103 | XCTFail("[\(testName)] Boolean pack should contains only 1 byte (\(packed.count) bytes found)")
104 | return
105 | }
106 |
107 | guard packed[0] == byte else {
108 | XCTFail("[\(testName)] Boolean pack is different from expected")
109 | return
110 | }
111 |
112 | guard let unpacked_value = try packed.unpack() else {
113 | XCTFail("[\(testName)] Failed to unpack boolean value")
114 | return
115 | }
116 |
117 | guard let bool_val = unpacked_value as? Bool else {
118 | XCTFail("[\(testName)] Failed to cast read value from pack to a valid Boolean type")
119 | return
120 | }
121 |
122 | guard bool_val == value else {
123 | XCTFail("[\(testName)] Packed boolean value is not valid")
124 | return
125 | }
126 |
127 | } catch let err {
128 | // Something went wrong while packing data
129 | XCTFail("[\(testName)] Failed to pack boolean: \(err) (src='\(value)')")
130 | return
131 | }
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/Tests/SwiftMsgPackTests/SwiftMsgPackTests_Data.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 | import Foundation
34 |
35 | import XCTest
36 | @testable import SwiftMsgPack
37 |
38 | class SwiftMsgPackTests_Data: XCTestCase {
39 |
40 | override func setUp() {
41 | super.setUp()
42 | }
43 |
44 | override func tearDown() {
45 | super.tearDown()
46 | }
47 |
48 | // MARK: - Test Data
49 |
50 | func test_shortData() {
51 | let len = 6
52 | let (data,exp) = generateTestData(len)
53 | performTestData(name: "Test Short Data", value: data, expected: exp)
54 | }
55 |
56 | func test_mediumData() {
57 | let len = Int( UInt16(UInt16.max - 1) )
58 | let (data,exp) = generateTestData(len)
59 | performTestData(name: "Test Medium Data", value: data, expected: exp)
60 | }
61 |
62 | func test_bigData() {
63 | let len = Int( UInt32(UInt16.max) + 1 )
64 | let (data,exp) = generateTestData(len)
65 | performTestData(name: "Test Long Data", value: data, expected: exp)
66 | }
67 |
68 | // MARK: - Helper Functions
69 |
70 | func generateTestData(_ length: Int) -> (Data,[UInt8]) {
71 | var bytes: [UInt8] = []
72 | let data_sequence: [UInt8] = generateRandomNumberSequence(length)
73 |
74 | if length < Int(UInt8.max) {
75 | // Header
76 | bytes.append(UInt8(0xc4))
77 | // Length
78 | bytes.append(UInt8(length))
79 | }
80 | else if length < Int(UInt16.max) {
81 | // Header
82 | bytes.append(UInt8(0xc5))
83 | // Length (big endian)
84 | bytes.append(UInt8((length >> 8) & 0xff))
85 | bytes.append(UInt8(length & 0xff))
86 | }
87 | else if length < Int(UInt32.max) {
88 | bytes.append(UInt8(0xc6))
89 | // Length (big endian)
90 | bytes.append(UInt8((length >> 24) & 0xff))
91 | bytes.append(UInt8((length >> 16) & 0xff))
92 | bytes.append(UInt8((length >> 8) & 0xff))
93 | bytes.append(UInt8(length & 0xff))
94 | }
95 | // Append real data
96 | bytes.append(contentsOf: data_sequence)
97 | // Get generated data
98 | let data = Data(data_sequence)
99 | return (data,bytes)
100 | }
101 |
102 | func generateRandomNumberSequence(_ length: Int) -> [UInt8] {
103 | var items: [UInt8] = []
104 | for _ in 0.. ([AnyHashable:Any?],[UInt8]) {
70 | var dict: [AnyHashable:Any?] = [:]
71 | var bytes: [UInt8] = []
72 |
73 | // Dictionary Header
74 | if length < 16 {
75 | // Header + Length
76 | bytes.append(UInt8(0x80 + length))
77 | }
78 | else if length < Int(UInt16.max) {
79 | // Header
80 | bytes.append(UInt8(0xde))
81 | // Length (big endian)
82 | bytes.append(UInt8((length >> 8) & 0xff))
83 | bytes.append(UInt8(length & 0xff))
84 | }
85 | else if length < Int(UInt32.max) {
86 | // Header
87 | bytes.append(UInt8(0xdf))
88 | // Length (big endian)
89 | bytes.append(UInt8((length >> 24) & 0xff))
90 | bytes.append(UInt8((length >> 16) & 0xff))
91 | bytes.append(UInt8((length >> 8) & 0xff))
92 | bytes.append(UInt8(length & 0xff))
93 | }
94 |
95 | for _ in 0.. (String,Any?,[UInt8]) {
108 | let type = randomValue(min: 0, max: 3)
109 | var item: Any?
110 | var bytes: [UInt8] = []
111 |
112 | // Key (to simplify we want to limit it, we have already test it in String test)
113 | let length_key = randomValue(min: 1, max: 15)
114 | let key_value = randomString(length: length_key)
115 | let key_header: UInt8 = UInt8(UInt8(0xa0) + UInt8(length_key))
116 | let encoded_key = key_value.data(using: String.Encoding.utf8)!
117 | bytes.append(key_header)
118 | bytes.append(contentsOf: [UInt8](encoded_key))
119 |
120 | // Value
121 |
122 | // Just to test some types
123 | switch type {
124 | case 0: // nil
125 | item = nil
126 |
127 | let header: UInt8 = UInt8(0xc0)
128 | bytes.append(header)
129 | case 1: // Boolean
130 | let bool_val = randomValue(min: 0, max: 1)
131 | item = (bool_val == 0 ? false : true)
132 |
133 | let header: UInt8 = (item as! Bool == true ? UInt8(0xc3) : UInt8(0xc2))
134 | bytes.append(header)
135 | case 2: // Int
136 | let int8Num = randomValue(min: 0, max: Int(Int8.max))
137 | item = int8Num
138 |
139 | let header: UInt8 = UInt8(int8Num & 0x7f)
140 | bytes.append(header)
141 | case 3: // Fixed String
142 | let random_len = randomValue(min: 1, max: 20)
143 | let str = randomString(length: random_len)
144 | item = str
145 |
146 | let header: UInt8 = UInt8(UInt8(0xa0) + UInt8(random_len))
147 | bytes.append(header)
148 |
149 | let encoded_data = str.data(using: String.Encoding.utf8)!
150 | bytes.append(contentsOf: [UInt8](encoded_data))
151 | default:
152 | break
153 | }
154 |
155 | return (key_value,item,bytes)
156 | }
157 |
158 |
159 | /// Generate a random string with passed length
160 | ///
161 | /// - Parameter length: length of the string
162 | /// - Returns: random alphanumeric string
163 | func randomString(length: Int) -> String {
164 | let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
165 | let len = UInt32(letters.length)
166 | var randomString = ""
167 | for _ in 0 ..< length {
168 | let rand = arc4random_uniform(len)
169 | var nextChar = letters.character(at: Int(rand))
170 | randomString += NSString(characters: &nextChar, length: 1) as String
171 | }
172 | return randomString
173 | }
174 |
175 |
176 | /// Generate a random number in a range
177 | ///
178 | /// - Parameters:
179 | /// - min: min value
180 | /// - max: max value
181 | /// - Returns: random value
182 | func randomValue(min: Int, max: Int) -> Int {
183 | return Int(arc4random_uniform(UInt32(max) - UInt32(min)) + UInt32(min))
184 | }
185 |
186 | func performTestOnDictionary(name testName: String, value: [AnyHashable:Any?], expected bytes: [UInt8]) {
187 |
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/Tests/SwiftMsgPackTests/SwiftMsgPackTests_Numeric.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 |
34 | import XCTest
35 | @testable import SwiftMsgPack
36 |
37 | class SwiftMsgPackTests_Numeric: XCTestCase {
38 |
39 | override func setUp() {
40 | super.setUp()
41 | }
42 |
43 | override func tearDown() {
44 | super.tearDown()
45 | }
46 |
47 | // MARK: - UInt8
48 |
49 | func testUInt8() {
50 | performTestUInt8(name: "Test UInt8 #1", value: UInt8(0), expected: [0])
51 | performTestUInt8(name: "Test UInt8 #2", value: UInt8(0xC), expected: [0xC])
52 | performTestUInt8(name: "Test UInt8 #3", value: UInt8(0x81), expected: [0xcc, 0x81])
53 | performTestUInt8(name: "Test UInt8 #4", value: UInt8.max, expected: [0xcc, UInt8.max])
54 | }
55 |
56 | // MARK: - Int8
57 |
58 | func testInt8() {
59 | performTestInt8(name: "Test Int8 #1", value: Int8.min, expected: [0xd0, 0x80])
60 | performTestInt8(name: "Test Int8 #2", value: (Int8.min + 1), expected: [0xd0, 0x81])
61 | performTestInt8(name: "Test Int8 #3", value: (Int8.min + 2), expected: [0xd0, 0x82])
62 | performTestInt8(name: "Test Int8 #4", value: Int8(-33), expected: [0xd0, 0xdf])
63 | performTestInt8(name: "Test Int8 #5", value: Int8(-32), expected: [0xe0])
64 | performTestInt8(name: "Test Int8 #6", value: Int8(-1), expected: [0xff])
65 | performTestInt8(name: "Test Int8 #7", value: Int8(0), expected: [0])
66 | performTestInt8(name: "Test Int8 #8", value: Int8.max - 1, expected: [0x7e])
67 | performTestInt8(name: "Test Int8 #9", value: Int8.max, expected: [0x7f])
68 | }
69 |
70 | // MARK: - UInt16
71 |
72 | func testUInt16() {
73 | performTestUInt16(name: "Test UInt16 #1", value: UInt16(0), expected: [0])
74 | performTestUInt16(name: "Test UInt16 #2", value: UInt16(0x7f), expected: [0x7f])
75 | performTestUInt16(name: "Test UInt16 #3", value: UInt16(0x80), expected: [0xcc, 0x80])
76 | performTestUInt16(name: "Test UInt16 #4", value: UInt16.max, expected: [0xcd, 0xff, 0xff])
77 | performTestUInt16(name: "Test UInt16 #5", value: UInt16(Int16.max) + 1, expected: [0xcd, 0x80, 0x0])
78 | performTestUInt16(name: "Test UInt16 #6", value: UInt16(UInt8.max), expected: [0xcc, UInt8.max])
79 | performTestUInt16(name: "Test UInt16 #7", value: UInt16(UInt8.max) + 1, expected: [0xcd, 0x01, 0x0])
80 | performTestUInt16(name: "Test UInt16 #8", value: UInt16(Int16.max) - 1, expected: [0xcd, 0x7f, 0xfe])
81 | performTestUInt16(name: "Test UInt16 #9", value: UInt16(Int16.max), expected: [0xcd, 0x7f, 0xff])
82 | }
83 |
84 | // MARK: - Int16
85 |
86 | func testInt16() {
87 | performTestInt16(name: "Test Int16 #1", value: Int16.min, expected: [0xd1, 0x80, 0])
88 | performTestInt16(name: "Test Int16 #2", value: Int16(-33), expected: [0xd0, 0xdf])
89 | performTestInt16(name: "Test Int16 #3", value: Int16(0), expected: [0])
90 | performTestInt16(name: "Test Int16 #4", value: Int16(Int8.max - 1), expected: [0x7e])
91 | performTestInt16(name: "Test Int16 #5", value: Int16.min + 1, expected: [0xd1, 0x80, 0x01])
92 | performTestInt16(name: "Test Int16 #6", value: Int16(Int8.min) - 1, expected: [0xd1, 0xff, 0x7f])
93 | performTestInt16(name: "Test Int16 #7", value: Int16(Int8.min), expected: [0xd0, 0x80])
94 | performTestInt16(name: "Test Int16 #8", value: Int16(Int8.min + 1), expected: [0xd0, 0x81])
95 | performTestInt16(name: "Test Int16 #9", value: Int16(-33), expected: [0xd0, 0xdf])
96 | performTestInt16(name: "Test Int16 #10", value: Int16(-32), expected: [0xe0])
97 | performTestInt16(name: "Test Int16 #11", value: Int16(-1), expected: [0xff])
98 | performTestInt16(name: "Test Int16 #12", value: Int16(0), expected: [0])
99 | performTestInt16(name: "Test Int16 #13", value: Int16(Int8.max - 1), expected: [0x7e])
100 | performTestInt16(name: "Test Int16 #14", value: Int16(Int8.max), expected: [0x7f])
101 | performTestInt16(name: "Test Int16 #15", value: Int16(Int8.max) + 1, expected: [0xcc, 0x80])
102 | performTestInt16(name: "Test Int16 #16", value: Int16.max - 1, expected: [0xd1, 0x7f, 0xfe])
103 | performTestInt16(name: "Test Int16 #17", value: Int16.max, expected: [0xd1, 0x7f, 0xff])
104 | }
105 |
106 | // MARK: - UInt32
107 |
108 | func testUInt32() {
109 | performTestUInt32(name: "Test UInt32 #1", value: UInt32(0), expected: [0])
110 | performTestUInt32(name: "Test UInt32 #2", value: UInt32(UInt8.max), expected: [0xcc, UInt8.max])
111 | performTestUInt32(name: "Test UInt32 #3", value: UInt32.max - 1, expected: [0xce, 0xff, 0xff, 0xff, 0xfe])
112 | performTestUInt32(name: "Test UInt32 #4", value: UInt32.max, expected: [0xce, 0xff, 0xff, 0xff, 0xff])
113 | performTestUInt32(name: "Test UInt32 #5", value: UInt32(UInt8.max), expected: [0xcc, UInt8.max])
114 | performTestUInt32(name: "Test UInt32 #6", value: UInt32(UInt8.max) + 1, expected: [0xcd, 0x01, 0x0])
115 | performTestUInt32(name: "Test UInt32 #7", value: UInt32(Int16.max) - 1, expected: [0xcd, 0x7f, 0xfe])
116 | performTestUInt32(name: "Test UInt32 #8", value: UInt32(Int16.max), expected: [0xcd, 0x7f, 0xff])
117 | performTestUInt32(name: "Test UInt32 #9", value: UInt32(Int16.max) + 1, expected: [0xcd, 0x80, 0x0])
118 | }
119 |
120 | // MARK: - Int32
121 |
122 | func testInt32() {
123 | performTestInt32(name: "Test Int32 #1", value: Int32.min, expected: [0xd2, 0x80, 0, 0, 0])
124 | performTestInt32(name: "Test Int32 #2", value: Int32(Int16.min) - 1, expected: [0xd2, 0xff, 0xff, 0x7f, 0xff])
125 | performTestInt32(name: "Test Int32 #3", value: Int32(Int8.min + 1), expected: [0xd0, 0x81])
126 | performTestInt32(name: "Test Int32 #4", value: Int32(Int8.max - 1), expected: [0x7e])
127 | performTestInt32(name: "Test Int32 #5", value: Int32(Int16.max), expected: [0xd1, 0x7f, 0xff])
128 | performTestInt32(name: "Test Int32 #6", value: Int32.max, expected: [0xd2, 0x7f, 0xff, 0xff, 0xff])
129 | performTestInt32(name: "Test Int32 #7", value: Int32.max - 1, expected: [0xd2, 0x7f, 0xff, 0xff, 0xfe])
130 | performTestInt32(name: "Test Int32 #8", value: Int32(Int16.max) + 1, expected: [0xcd, 0x80, 0])
131 | performTestInt32(name: "Test Int32 #9", value: Int32(-33), expected: [0xd0, 0xdf])
132 | performTestInt32(name: "Test Int32 #10", value: Int32(-32), expected: [0xe0])
133 | performTestInt32(name: "Test Int32 #11", value: Int32(-1), expected: [0xff])
134 | performTestInt32(name: "Test Int32 #12", value: Int32(Int8.max), expected: [0x7f])
135 | }
136 |
137 | // MARK: - UInt64
138 |
139 | func testUInt64() {
140 | performTestUInt64(name: "Test UInt64 #1", value: UInt64(0), expected: [0])
141 | performTestUInt64(name: "Test UInt64 #2", value: UInt64(0x81), expected: [0xcc, 0x81])
142 | performTestUInt64(name: "Test UInt64 #3", value: UInt64.max, expected: [0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143 | 0xff])
144 | performTestUInt64(name: "Test UInt64 #5", value: UInt64(Int32.max) + 1, expected: [0xce, 0x80, 0x0, 0x0, 0x0])
145 | performTestUInt64(name: "Test UInt64 #6", value: UInt64.max - 1, expected: [0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146 | 0xfe])
147 | performTestUInt64(name: "Test UInt64 #7", value: UInt64.max, expected: [0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
148 | 0xff])
149 | performTestUInt64(name: "Test UInt64 #7", value: UInt64(Int32.max), expected: [0xce, 0x7f, 0xff, 0xff, 0xff])
150 | }
151 |
152 | // MARK: - Int64
153 |
154 | func testInt64() {
155 | performTestInt64(name: "Test Int64 #1", value: Int64.min, expected: [0xd3, 0x80, 0, 0, 0, 0, 0, 0, 0])
156 | performTestInt64(name: "Test Int64 #2", value: Int64.min + 1, expected: [0xd3, 0x80, 0, 0, 0, 0, 0, 0, 0x01])
157 | performTestInt64(name: "Test Int64 #3", value: Int64(Int32.min) - 1, expected: [0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff,
158 | 0xff])
159 | performTestInt64(name: "Test Int64 #4", value: Int64(Int32.min), expected: [0xd2, 0x80, 0, 0, 0])
160 | performTestInt64(name: "Test Int64 #5", value: Int64(Int32.min) + 1, expected: [0xd2, 0x80, 0, 0, 0x01])
161 | performTestInt64(name: "Test Int64 #6", value: Int64(Int16.min) - 1, expected: [0xd2, 0xff, 0xff, 0x7f, 0xff])
162 | performTestInt64(name: "Test Int64 #7", value: Int64(Int16.min), expected: [0xd1, 0x80, 0])
163 | performTestInt64(name: "Test Int64 #8", value: Int64(Int16.min) + 1, expected: [0xd1, 0x80, 0x01])
164 | performTestInt64(name: "Test Int64 #10", value: Int64(Int8.min), expected: [0xd0, 0x80])
165 | performTestInt64(name: "Test Int64 #11", value: Int64(Int8.min) - 1, expected: [0xd1, 0xff, 0x7f])
166 | performTestInt64(name: "Test Int64 #12", value: Int64(Int8.min) + 1, expected: [0xd0, 0x81])
167 | performTestInt64(name: "Test Int64 #13", value: Int64(Int8.max), expected: [0x7f])
168 |
169 | performTestInt64(name: "Test Int64 #14", value: Int64(Int8.max - 1), expected: [0x7e])
170 | performTestInt64(name: "Test Int64 #15", value: Int64(Int8.max), expected: [0x7f])
171 | performTestInt64(name: "Test Int64 #16", value: Int64(Int8.max) + 1, expected: [0xcc, 0x80])
172 | performTestInt64(name: "Test Int64 #17", value: Int64(Int16.max) - 1, expected: [0xd1, 0x7f, 0xfe])
173 | performTestInt64(name: "Test Int64 #18", value: Int64(Int16.max), expected: [0xd1, 0x7f, 0xff])
174 | performTestInt64(name: "Test Int64 #19", value: Int64(Int16.max) + 1, expected: [0xcd, 0x80, 0])
175 |
176 | performTestInt64(name: "Test Int64 #20", value: Int64.max, expected: [0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
177 | 0xff])
178 | performTestInt64(name: "Test Int64 #21", value: Int64.max - 1, expected: [0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
179 | 0xfe])
180 |
181 | }
182 |
183 | // MARK: - Float
184 |
185 | func testFloat() {
186 | performTestFloat(name: "Test Float #1", value: Float(1.5), expected: [0xca, 0x3f, 0xc0, 0, 0])
187 | performTestFloat(name: "Test Float #2", value: Float(-553.4), expected: [0xca, 0xc4, 0x0a, 0x59, 0x9a])
188 | performTestFloat(name: "Test Float #3", value: Float(9124.45789), expected: [0xca, 0x46, 0x0e, 0x91, 0xd5])
189 | }
190 |
191 | // MARK: - Double
192 |
193 | func testDouble() {
194 | performTestDouble(name: "Test Double #1", value: Double(0.0), expected: [0xcb, 0, 0, 0, 0, 0, 0, 0, 0])
195 | performTestDouble(name: "Test Double #2", value: Double(2.5), expected: [0xcb, 0x40, 0x04, 0, 0, 0, 0, 0, 0])
196 | performTestDouble(name: "Test Double #3", value: Double(-553.4), expected: [0xcb, 0xc0, 0x81, 0x4b, 0x33, 0x33, 0x33, 0x33, 0x33])
197 | performTestDouble(name: "Test Double #4", value: Double(998.345), expected: [0xcb, 0x40, 0x8f, 0x32, 0xc2, 0x8f, 0x5c, 0x28, 0xf6])
198 | }
199 |
200 | // MARK: - Helper Functions
201 |
202 | func performTestDouble(name testName: String, value: Double, expected bytes: [UInt8]) {
203 | var packed = Data()
204 |
205 | do {
206 | try packed.pack(value)
207 |
208 | guard packed.count == bytes.count else {
209 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
210 | return
211 | }
212 |
213 | var idx = 0
214 | for byte in packed {
215 | guard byte == bytes[idx] else {
216 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
217 | return
218 | }
219 | idx += 1
220 | }
221 |
222 | guard let unpacked = try packed.unpack() else {
223 | XCTFail("[\(testName)] Failed to unpack")
224 | return
225 | }
226 |
227 | guard let value_float = unpacked as? Double else {
228 | XCTFail("[\(testName)] Failed to cast value to a valid Double type")
229 | return
230 | }
231 |
232 | guard value_float == value else {
233 | XCTFail("[\(testName)] Unpacked value is different from the original")
234 | return
235 | }
236 |
237 | } catch let err {
238 | // Something went wrong while packing data
239 | XCTFail("[\(testName)] Failed to pack Double: \(err) (src='\(value)')")
240 | return
241 | }
242 | }
243 |
244 | func performTestFloat(name testName: String, value: Float, expected bytes: [UInt8]) {
245 | var packed = Data()
246 |
247 | do {
248 | try packed.pack(value)
249 |
250 | guard packed.count == bytes.count else {
251 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
252 | return
253 | }
254 |
255 | var idx = 0
256 | for byte in packed {
257 | guard byte == bytes[idx] else {
258 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
259 | return
260 | }
261 | idx += 1
262 | }
263 |
264 | guard let unpacked = try packed.unpack() else {
265 | XCTFail("[\(testName)] Failed to unpack")
266 | return
267 | }
268 |
269 | guard let value_float = unpacked as? Float else {
270 | XCTFail("[\(testName)] Failed to cast value to a valid Float type")
271 | return
272 | }
273 |
274 | guard value_float == value else {
275 | XCTFail("[\(testName)] Unpacked value is different from the original")
276 | return
277 | }
278 |
279 | } catch let err {
280 | // Something went wrong while packing data
281 | XCTFail("[\(testName)] Failed to pack Float: \(err) (src='\(value)')")
282 | return
283 | }
284 | }
285 |
286 | func performTestInt64(name testName: String, value: Int64, expected bytes: [UInt8]) {
287 | var packed = Data()
288 | do {
289 | try packed.pack(value)
290 |
291 | guard packed.count == bytes.count else {
292 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
293 | return
294 | }
295 |
296 | var idx = 0
297 | for byte in packed {
298 | guard byte == bytes[idx] else {
299 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
300 | return
301 | }
302 | idx += 1
303 | }
304 |
305 | guard let unpacked = try packed.unpack() else {
306 | XCTFail("[\(testName)] Failed to unpack")
307 | return
308 | }
309 |
310 | var value_Int64: Int64
311 | if let tmpval = unpacked as? UInt64 {
312 | value_Int64 = Int64(bitPattern: tmpval)
313 | } else if let tmpval = unpacked as? Int64 {
314 | value_Int64 = tmpval
315 | } else if let tmpval = unpacked as? UInt32 {
316 | value_Int64 = Int64(tmpval)
317 | } else if let tmpval = unpacked as? Int32 {
318 | value_Int64 = Int64(tmpval)
319 | } else if let tmpval = unpacked as? UInt16 {
320 | value_Int64 = Int64(tmpval)
321 | } else if let tmpval = unpacked as? Int16 {
322 | value_Int64 = Int64(tmpval)
323 | } else if let tmpval = unpacked as? UInt8 {
324 | value_Int64 = Int64(tmpval)
325 | } else if let tmpval = unpacked as? Int8 {
326 | value_Int64 = Int64(tmpval)
327 | } else {
328 | XCTFail("[\(testName)] Failed to cast value to a valid Int64")
329 | return
330 | }
331 |
332 | guard value_Int64 == value else {
333 | XCTFail("[\(testName)] Unpacked value is different from the original")
334 | return
335 | }
336 |
337 | } catch let err {
338 | // Something went wrong while packing data
339 | XCTFail("[\(testName)] Failed to pack UInt64: \(err) (src='\(value)')")
340 | return
341 | }
342 | }
343 |
344 | func performTestUInt64(name testName: String, value: UInt64, expected bytes: [UInt8]) {
345 | var packed = Data()
346 | do {
347 | try packed.pack(value)
348 |
349 | guard packed.count == bytes.count else {
350 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
351 | return
352 | }
353 |
354 | var idx = 0
355 | for byte in packed {
356 | guard byte == bytes[idx] else {
357 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
358 | return
359 | }
360 | idx += 1
361 | }
362 |
363 | guard let unpacked = try packed.unpack() else {
364 | XCTFail("[\(testName)] Failed to unpack")
365 | return
366 | }
367 |
368 | var value_UInt64: UInt64
369 | if let value = unpacked as? UInt64 {
370 | value_UInt64 = value
371 | } else if let value = unpacked as? Int64 {
372 | value_UInt64 = UInt64(value)
373 | } else if let value = unpacked as? UInt32 {
374 | value_UInt64 = UInt64(value)
375 | } else if let value = unpacked as? Int32 {
376 | value_UInt64 = UInt64(value)
377 | } else if let value = unpacked as? UInt16 {
378 | value_UInt64 = UInt64(value)
379 | } else if let value = unpacked as? Int16 {
380 | value_UInt64 = UInt64(value)
381 | } else if let value = unpacked as? UInt8 {
382 | value_UInt64 = UInt64(value)
383 | } else if let value = unpacked as? Int8 {
384 | value_UInt64 = UInt64(value)
385 | } else {
386 | XCTFail("[\(testName)] Failed to cast value to a valid UInt64")
387 | return
388 | }
389 |
390 | guard value_UInt64 == value else {
391 | XCTFail("[\(testName)] Unpacked value is different from the original")
392 | return
393 | }
394 |
395 | } catch let err {
396 | // Something went wrong while packing data
397 | XCTFail("[\(testName)] Failed to pack UInt64: \(err) (src='\(value)')")
398 | return
399 | }
400 | }
401 |
402 | func performTestInt32(name testName: String, value: Int32, expected bytes: [UInt8]) {
403 | var packed = Data()
404 | do {
405 | try packed.pack(value)
406 |
407 | guard packed.count == bytes.count else {
408 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
409 | return
410 | }
411 |
412 | var idx = 0
413 | for byte in packed {
414 | guard byte == bytes[idx] else {
415 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
416 | return
417 | }
418 | idx += 1
419 | }
420 |
421 | guard let unpacked = try packed.unpack() else {
422 | XCTFail("[\(testName)] Failed to unpack")
423 | return
424 | }
425 |
426 | var value_Int32: Int32
427 | if let value = unpacked as? UInt32 {
428 | value_Int32 = Int32(bitPattern: value)
429 | } else if let value = unpacked as? Int32 {
430 | value_Int32 = value
431 | } else if let value = unpacked as? UInt16 {
432 | value_Int32 = Int32(value)
433 | } else if let value = unpacked as? Int16 {
434 | value_Int32 = Int32(value)
435 | } else if let value = unpacked as? UInt8 {
436 | value_Int32 = Int32(value)
437 | } else if let value = unpacked as? Int8 {
438 | value_Int32 = Int32(value)
439 | } else {
440 | XCTFail("[\(testName)] Failed to cast value to a valid Int32")
441 | return
442 | }
443 |
444 | guard value_Int32 == value else {
445 | XCTFail("[\(testName)] Unpacked value is different from the original")
446 | return
447 | }
448 |
449 | } catch let err {
450 | // Something went wrong while packing data
451 | XCTFail("[\(testName)] Failed to pack Int32: \(err) (src='\(value)')")
452 | return
453 | }
454 | }
455 |
456 | func performTestUInt32(name testName: String, value: UInt32, expected bytes: [UInt8]) {
457 | var packed = Data()
458 | do {
459 | try packed.pack(value)
460 |
461 | guard packed.count == bytes.count else {
462 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
463 | return
464 | }
465 |
466 | var idx = 0
467 | for byte in packed {
468 | guard byte == bytes[idx] else {
469 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
470 | return
471 | }
472 | idx += 1
473 | }
474 |
475 | guard let unpacked = try packed.unpack() else {
476 | XCTFail("[\(testName)] Failed to unpack")
477 | return
478 | }
479 |
480 | var value_UInt32: UInt32
481 | if let val = unpacked as? UInt32 {
482 | value_UInt32 = val
483 | } else if let val = unpacked as? Int32 {
484 | value_UInt32 = UInt32(val)
485 | } else if let val = unpacked as? UInt16 {
486 | value_UInt32 = UInt32(val)
487 | } else if let val = unpacked as? Int16 {
488 | value_UInt32 = UInt32(val)
489 | } else if let val = unpacked as? UInt8 {
490 | value_UInt32 = UInt32(val)
491 | } else if let val = unpacked as? Int8 {
492 | value_UInt32 = UInt32(val)
493 | } else {
494 | XCTFail("[\(testName)] Failed to cast value to a valid UInt32")
495 | return
496 | }
497 |
498 | guard value_UInt32 == value else {
499 | XCTFail("[\(testName)] Unpacked value is different from the original")
500 | return
501 | }
502 |
503 | } catch let err {
504 | // Something went wrong while packing data
505 | XCTFail("[\(testName)] Failed to pack UInt32: \(err) (src='\(value)')")
506 | return
507 | }
508 | }
509 |
510 | func performTestInt16(name testName: String, value: Int16, expected bytes: [UInt8]) {
511 | var packed = Data()
512 | do {
513 | try packed.pack(value)
514 |
515 | guard packed.count == bytes.count else {
516 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
517 | return
518 | }
519 |
520 | var idx = 0
521 | for byte in packed {
522 | guard byte == bytes[idx] else {
523 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
524 | return
525 | }
526 | idx += 1
527 | }
528 |
529 | guard let unpacked = try packed.unpack() else {
530 | XCTFail("[\(testName)] Failed to unpack")
531 | return
532 | }
533 |
534 | var value_Int16: Int16
535 | if let value = unpacked as? UInt16 {
536 | value_Int16 = Int16(value)
537 | } else if let value = unpacked as? Int16 {
538 | value_Int16 = Int16(value)
539 | } else if let value = unpacked as? UInt8 {
540 | value_Int16 = Int16(value)
541 | } else if let value = unpacked as? Int8 {
542 | value_Int16 = Int16(value)
543 | } else {
544 | XCTFail("[\(testName)] Failed to cast value to a valid Int16")
545 | return
546 | }
547 |
548 | guard value_Int16 == value else {
549 | XCTFail("[\(testName)] Unpacked value is different from the original")
550 | return
551 | }
552 |
553 | } catch let err {
554 | // Something went wrong while packing data
555 | XCTFail("[\(testName)] Failed to pack Int16: \(err) (src='\(value)')")
556 | return
557 | }
558 | }
559 |
560 | func performTestUInt16(name testName: String, value: UInt16, expected bytes: [UInt8]) {
561 | var packed = Data()
562 | do {
563 | try packed.pack(value)
564 |
565 | guard packed.count == bytes.count else {
566 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
567 | return
568 | }
569 |
570 | var idx = 0
571 | for byte in packed {
572 | guard byte == bytes[idx] else {
573 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
574 | return
575 | }
576 | idx += 1
577 | }
578 |
579 | guard let unpacked = try packed.unpack() else {
580 | XCTFail("[\(testName)] Failed to unpack")
581 | return
582 | }
583 |
584 | var value_uInt16: UInt16
585 | if let val = unpacked as? UInt16 {
586 | value_uInt16 = val
587 | } else if let val = unpacked as? Int16 {
588 | value_uInt16 = UInt16(val)
589 | } else if let val = unpacked as? UInt8 {
590 | value_uInt16 = UInt16(val)
591 | } else if let val = unpacked as? Int8 {
592 | value_uInt16 = UInt16(val)
593 | } else {
594 | XCTFail("[\(testName)] Failed to cast value to a valid UInt16")
595 | return
596 | }
597 |
598 | guard value_uInt16 == value else {
599 | XCTFail("[\(testName)] Unpacked value is different from the original")
600 | return
601 | }
602 |
603 | } catch let err {
604 | // Something went wrong while packing data
605 | XCTFail("[\(testName)] Failed to pack UInt16: \(err) (src='\(value)')")
606 | return
607 | }
608 | }
609 |
610 | func performTestInt8(name testName: String, value: Int8, expected bytes: [UInt8]) {
611 | var packed = Data()
612 | do {
613 | try packed.pack(value)
614 |
615 | guard packed.count == bytes.count else {
616 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
617 | return
618 | }
619 |
620 | var idx = 0
621 | for byte in packed {
622 | guard byte == bytes[idx] else {
623 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
624 | return
625 | }
626 | idx += 1
627 | }
628 |
629 | guard let unpacked = try packed.unpack() else {
630 | XCTFail("[\(testName)] Failed to unpack")
631 | return
632 | }
633 |
634 | guard let unpacked_value = unpacked as? Int8 else {
635 | XCTFail("[\(testName)] Failed to unpack to a valid Int8")
636 | return
637 | }
638 |
639 |
640 | guard unpacked_value == value else {
641 | XCTFail("[\(testName)] Unpacked value is not equal to the original value")
642 | return
643 | }
644 |
645 | } catch let err {
646 | // Something went wrong while packing data
647 | XCTFail("[\(testName)] Failed to pack Int8: \(err) (src='\(value)')")
648 | return
649 | }
650 | }
651 |
652 | func performTestUInt8(name testName: String, value: UInt8, expected bytes: [UInt8]) {
653 | var packed = Data()
654 | do {
655 | try packed.pack(value)
656 |
657 | guard packed.count == bytes.count else {
658 | XCTFail("[\(testName)] Packed value different from expected data (\(packed.count) bytes, \(bytes.count) expected)")
659 | return
660 | }
661 |
662 | var idx = 0
663 | for byte in packed {
664 | guard byte == bytes[idx] else {
665 | XCTFail("[\(testName)] Byte \(idx) is different from expected (\(byte), \(bytes[idx]) expected")
666 | return
667 | }
668 | idx += 1
669 | }
670 |
671 | guard let unpacked = try packed.unpack() else {
672 | XCTFail("[\(testName)] Failed to unpack")
673 | return
674 | }
675 |
676 | var unpacked_value: UInt8
677 | if let tmpval = unpacked as? UInt8 {
678 | unpacked_value = tmpval
679 | } else if let tmpval = unpacked as? Int8 {
680 | unpacked_value = UInt8(tmpval)
681 | } else {
682 | XCTFail("[\(testName)] Failed to unpack to a valid UIn8")
683 | return
684 | }
685 |
686 |
687 | guard unpacked_value == value else {
688 | XCTFail("[\(testName)] Unpacked value is not equal to the original value")
689 | return
690 | }
691 |
692 | } catch let err {
693 | // Something went wrong while packing data
694 | XCTFail("[\(testName)] Failed to pack uInt8: \(err) (src='\(value)')")
695 | return
696 | }
697 | }
698 |
699 | }
700 |
--------------------------------------------------------------------------------
/Tests/SwiftMsgPackTests/SwiftMsgPackTests_String.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * SwiftMsgPack
3 | * Lightweight MsgPack for Swift
4 | *
5 | * Created by: Daniele Margutti
6 | * Email: hello@danielemargutti.com
7 | * Web: http://www.danielemargutti.com
8 | * Twitter: @danielemargutti
9 | *
10 | * Copyright © 2017 Daniele Margutti
11 | *
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining a copy
14 | * of this software and associated documentation files (the "Software"), to deal
15 | * in the Software without restriction, including without limitation the rights
16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the Software is
18 | * furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in
21 | * all copies or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | * THE SOFTWARE.
30 | *
31 | */
32 |
33 |
34 | import XCTest
35 | @testable import SwiftMsgPack
36 |
37 | class SwiftMsgPackTests_String: XCTestCase {
38 |
39 | override func setUp() {
40 | super.setUp()
41 | }
42 |
43 | override func tearDown() {
44 | super.tearDown()
45 | }
46 |
47 | // MARK: - Tests
48 |
49 | // Test empty string
50 | func test_emptyString() {
51 | performTest(name: "Empty String", string: "", expected: [0xa0])
52 | }
53 |
54 | // Test a short string (less than 32)
55 | func test_tinyString() {
56 | let (src,expectedValues) = generateTestString(25)
57 | performTest(name: "Tiny String", string: src, expected: expectedValues)
58 | }
59 |
60 | // Test a short string (UInt8.max - 1)
61 | func test_shortString() {
62 | let length: Int = Int( (UInt8.max - 1) )
63 | let (src,expectedValues) = generateTestString(length)
64 | performTest(name: "Short String", string: src, expected: expectedValues)
65 | }
66 |
67 | // Test a short string UInt16(UInt16.max - 1)
68 | func test_mediumString() {
69 | let length: Int = Int( UInt16(UInt16.max - 1) )
70 | let (src,expectedValues) = generateTestString(length)
71 | performTest(name: "Medium String", string: src, expected: expectedValues)
72 | }
73 |
74 | // Test a short string UInt32(UInt16.max) + 1
75 | func test_longString() {
76 | let length: Int = Int( UInt32(UInt16.max) + 1 )
77 | let (src,expectedValues) = generateTestString(length)
78 | performTest(name: "Long String", string: src, expected: expectedValues)
79 | }
80 |
81 | // MARK: - Helper Functions
82 |
83 | /// Generare a string to test
84 | ///
85 | /// - Parameter length: length of the string
86 | /// - Returns: random string and expected bytes of the sequence
87 | func generateTestString(_ length: Int) -> (String,[UInt8]) {
88 | // generate a random string and put it in an array of UInt8
89 | let src_string = randomString(length: length)
90 | var bytes: [UInt8] = []
91 |
92 | // Append correct header to the start of bytes sequence
93 | if length < 32 {
94 | // Header + Length
95 | bytes.append(UInt8(0xa0 + length))
96 | }
97 | else if length < Int(UInt8.max) {
98 | // Header
99 | bytes.append(UInt8(0xd9))
100 |
101 | // Length of the data
102 | bytes.append(UInt8(length))
103 | }
104 | else if length < Int(UInt16.max) {
105 | // Header
106 | bytes.append(UInt8(0xda))
107 |
108 | // Length of the data
109 | bytes.append(UInt8((length >> 8) & 0xff))
110 | bytes.append(UInt8(length & 0xff))
111 | }
112 | else if length < Int(UInt32.max) {
113 | // Header
114 | bytes.append(UInt8(0xdb))
115 |
116 | // Length of the data
117 | bytes.append(UInt8((length >> 24) & 0xff))
118 | bytes.append(UInt8((length >> 16) & 0xff))
119 | bytes.append(UInt8((length >> 8) & 0xff))
120 | bytes.append(UInt8(length & 0xff))
121 | }
122 |
123 | // Append data
124 | bytes.append(contentsOf: [UInt8](src_string.utf8))
125 | return (src_string,bytes)
126 | }
127 |
128 |
129 | /// Generate a random string with passed length
130 | ///
131 | /// - Parameter length: length of the string
132 | /// - Returns: randome alphanumeric string
133 | func randomString(length: Int) -> String {
134 | let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
135 | let len = UInt32(letters.length)
136 | var randomString = ""
137 | for _ in 0 ..< length {
138 | let rand = arc4random_uniform(len)
139 | var nextChar = letters.character(at: Int(rand))
140 | randomString += NSString(characters: &nextChar, length: 1) as String
141 | }
142 | return randomString
143 | }
144 |
145 |
146 | /// Perform test on string and validate result
147 | ///
148 | /// - Parameters:
149 | /// - testName: name of the test
150 | /// - value: source string
151 | /// - bytes: expected packed bytes to validate
152 | func performTest(name testName: String, string value: String, expected bytes: [UInt8]) {
153 | var packed = Data()
154 | do {
155 | // Try to pack data
156 | try packed.pack(value)
157 |
158 | // Validate the number of bytes between packed version and expected version
159 | guard packed.count == bytes.count else {
160 | XCTFail("[\(testName)] Pack failed, different number of bytes than expected - \(packed.count), \(bytes.count) expected")
161 | return
162 | }
163 |
164 | // Now validates each byte
165 | var idx = 0
166 | for byte in packed {
167 | guard byte == packed[idx] else {
168 | XCTFail("[\(testName)] Pack failed, byte \(idx) is different from expected (\(packed[idx]) != \(byte))")
169 | return
170 | }
171 | idx += 1
172 | }
173 |
174 | // Try to unpack and validate the result
175 | guard let unpacked = try packed.unpack() else {
176 | XCTFail("[\(testName)] Failed to unpack packed data")
177 | return
178 | }
179 | guard let str_value = unpacked as? String else {
180 | XCTFail("[\(testName)] Failed to cast unpacked data to a valid String instance")
181 | return
182 | }
183 | guard str_value.count == value.count else {
184 | XCTFail("[\(testName)] Unpacked string has a different number of characters than source")
185 | return
186 | }
187 | guard str_value == value else {
188 | XCTFail("[\(testName)] Unpacked string is different from source")
189 | return
190 | }
191 |
192 | } catch let error {
193 | // Something went wrong while packing data
194 | XCTFail("[\(testName)] Failed to pack string: \(error) (src='\(value)')")
195 | return
196 | }
197 | }
198 |
199 | }
200 |
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/SwiftMsgPack/6a9b7d73f78cd0f7e5ad280fde39a347f15baaf7/banner.png
--------------------------------------------------------------------------------