├── .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 | SwiftLocation 3 |

4 | 5 |

It's like JSON, but faster!

6 | 7 | 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![CI Status](https://travis-ci.org/malcommac/SwiftMsgPack.svg)](https://travis-ci.org/malcommac/SwiftMsgPack) [![Version](https://img.shields.io/cocoapods/v/SwiftMsgPack.svg?style=flat)](http://cocoadocs.org/docsets/SwiftMsgPack) [![License](https://img.shields.io/cocoapods/l/SwiftMsgPack.svg?style=flat)](http://cocoadocs.org/docsets/SwiftMsgPack) [![Platform](https://img.shields.io/cocoapods/p/SwiftMsgPack.svg?style=flat)](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 --------------------------------------------------------------------------------