Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
//  SwiftyJSON.swift
2
//
3
//  Copyright (c) 2014 - 2017 Ruoyu Fu, Pinglin Tang
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
13
//  all 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
21
//  THE SOFTWARE.
22
 
23
import Foundation
24
 
25
// MARK: - Error
26
// swiftlint:disable line_length
27
public enum SwiftyJSONError: Int, Swift.Error {
28
    case unsupportedType = 999
29
    case indexOutOfBounds = 900
30
    case elementTooDeep = 902
31
    case wrongType = 901
32
    case notExist = 500
33
    case invalidJSON = 490
34
}
35
 
36
extension SwiftyJSONError: CustomNSError {
37
 
38
    /// return the error domain of SwiftyJSONError
39
    public static var errorDomain: String { return "com.swiftyjson.SwiftyJSON" }
40
 
41
    /// return the error code of SwiftyJSONError
42
    public var errorCode: Int { return self.rawValue }
43
 
44
    /// return the userInfo of SwiftyJSONError
45
    public var errorUserInfo: [String: Any] {
46
        switch self {
47
        case .unsupportedType:
48
            return [NSLocalizedDescriptionKey: "It is an unsupported type."]
49
        case .indexOutOfBounds:
50
            return [NSLocalizedDescriptionKey: "Array Index is out of bounds."]
51
        case .wrongType:
52
            return [NSLocalizedDescriptionKey: "Couldn't merge, because the JSONs differ in type on top level."]
53
        case .notExist:
54
            return [NSLocalizedDescriptionKey: "Dictionary key does not exist."]
55
        case .invalidJSON:
56
            return [NSLocalizedDescriptionKey: "JSON is invalid."]
57
        case .elementTooDeep:
58
            return [NSLocalizedDescriptionKey: "Element too deep. Increase maxObjectDepth and make sure there is no reference loop."]
59
        }
60
    }
61
}
62
 
63
// MARK: - JSON Type
64
 
65
/**
66
JSON's type definitions.
67
 
68
See http://www.json.org
69
*/
70
public enum Type: Int {
71
	case number
72
	case string
73
	case bool
74
	case array
75
	case dictionary
76
	case null
77
	case unknown
78
}
79
 
80
// MARK: - JSON Base
81
 
82
public struct JSON {
83
 
84
	/**
85
	 Creates a JSON using the data.
86
 
87
	 - parameter data: The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
88
	 - parameter opt: The JSON serialization reading options. `[]` by default.
89
 
90
	 - returns: The created JSON
91
	 */
92
    public init(data: Data, options opt: JSONSerialization.ReadingOptions = []) throws {
93
        let object: Any = try JSONSerialization.jsonObject(with: data, options: opt)
94
        self.init(jsonObject: object)
95
    }
96
 
97
    /**
98
	 Creates a JSON object
99
	 - note: this does not parse a `String` into JSON, instead use `init(parseJSON: String)`
100
 
101
	 - parameter object: the object
102
 
103
	 - returns: the created JSON object
104
	 */
105
    public init(_ object: Any) {
106
        switch object {
107
        case let object as Data:
108
            do {
109
                try self.init(data: object)
110
            } catch {
111
                self.init(jsonObject: NSNull())
112
            }
113
        default:
114
            self.init(jsonObject: object)
115
        }
116
    }
117
 
118
	/**
119
	 Parses the JSON string into a JSON object
120
 
121
	 - parameter json: the JSON string
122
 
123
	 - returns: the created JSON object
124
	*/
125
	public init(parseJSON jsonString: String) {
126
		if let data = jsonString.data(using: .utf8) {
127
			self.init(data)
128
		} else {
129
			self.init(NSNull())
130
		}
131
	}
132
 
133
	/**
134
	 Creates a JSON using the object.
135
 
136
	 - parameter jsonObject:  The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
137
 
138
	 - returns: The created JSON
139
	 */
140
    fileprivate init(jsonObject: Any) {
141
        object = jsonObject
142
    }
143
 
144
	/**
145
	 Merges another JSON into this JSON, whereas primitive values which are not present in this JSON are getting added,
146
	 present values getting overwritten, array values getting appended and nested JSONs getting merged the same way.
147
 
148
	 - parameter other: The JSON which gets merged into this JSON
149
 
150
	 - throws `ErrorWrongType` if the other JSONs differs in type on the top level.
151
	 */
152
    public mutating func merge(with other: JSON) throws {
153
        try self.merge(with: other, typecheck: true)
154
    }
155
 
156
	/**
157
	 Merges another JSON into this JSON and returns a new JSON, whereas primitive values which are not present in this JSON are getting added,
158
	 present values getting overwritten, array values getting appended and nested JSONS getting merged the same way.
159
 
160
	 - parameter other: The JSON which gets merged into this JSON
161
 
162
	 - throws `ErrorWrongType` if the other JSONs differs in type on the top level.
163
 
164
	 - returns: New merged JSON
165
	 */
166
    public func merged(with other: JSON) throws -> JSON {
167
        var merged = self
168
        try merged.merge(with: other, typecheck: true)
169
        return merged
170
    }
171
 
172
    /**
173
     Private woker function which does the actual merging
174
     Typecheck is set to true for the first recursion level to prevent total override of the source JSON
175
 	*/
176
 	fileprivate mutating func merge(with other: JSON, typecheck: Bool) throws {
177
        if type == other.type {
178
            switch type {
179
            case .dictionary:
180
                for (key, _) in other {
181
                    try self[key].merge(with: other[key], typecheck: false)
182
                }
183
            case .array:
184
                self = JSON(arrayValue + other.arrayValue)
185
            default:
186
                self = other
187
            }
188
        } else {
189
            if typecheck {
190
                throw SwiftyJSONError.wrongType
191
            } else {
192
                self = other
193
            }
194
        }
195
    }
196
 
197
    /// Private object
198
    fileprivate var rawArray: [Any] = []
199
    fileprivate var rawDictionary: [String: Any] = [:]
200
    fileprivate var rawString: String = ""
201
    fileprivate var rawNumber: NSNumber = 0
202
    fileprivate var rawNull: NSNull = NSNull()
203
    fileprivate var rawBool: Bool = false
204
 
205
    /// JSON type, fileprivate setter
206
    public fileprivate(set) var type: Type = .null
207
 
208
    /// Error in JSON, fileprivate setter
209
    public fileprivate(set) var error: SwiftyJSONError?
210
 
211
    /// Object in JSON
212
    public var object: Any {
213
        get {
214
            switch type {
215
            case .array:      return rawArray
216
            case .dictionary: return rawDictionary
217
            case .string:     return rawString
218
            case .number:     return rawNumber
219
            case .bool:       return rawBool
220
            default:          return rawNull
221
            }
222
        }
223
        set {
224
            error = nil
225
            switch unwrap(newValue) {
226
            case let number as NSNumber:
227
                if number.isBool {
228
                    type = .bool
229
                    rawBool = number.boolValue
230
                } else {
231
                    type = .number
232
                    rawNumber = number
233
                }
234
            case let string as String:
235
                type = .string
236
                rawString = string
237
            case _ as NSNull:
238
                type = .null
239
            case nil:
240
                type = .null
241
            case let array as [Any]:
242
                type = .array
243
                rawArray = array
244
            case let dictionary as [String: Any]:
245
                type = .dictionary
246
                rawDictionary = dictionary
247
            default:
248
                type = .unknown
249
                error = SwiftyJSONError.unsupportedType
250
            }
251
        }
252
    }
253
 
254
    /// The static null JSON
255
    @available(*, unavailable, renamed:"null")
256
    public static var nullJSON: JSON { return null }
257
    public static var null: JSON { return JSON(NSNull()) }
258
}
259
 
260
/// Private method to unwarp an object recursively
261
private func unwrap(_ object: Any) -> Any {
262
    switch object {
263
    case let json as JSON:
264
        return unwrap(json.object)
265
    case let array as [Any]:
266
        return array.map(unwrap)
267
    case let dictionary as [String: Any]:
268
        var d = dictionary
269
        dictionary.forEach { pair in
270
            d[pair.key] = unwrap(pair.value)
271
        }
272
        return d
273
    default:
274
        return object
275
    }
276
}
277
 
278
public enum Index<T: Any>: Comparable {
279
    case array(Int)
280
    case dictionary(DictionaryIndex<String, T>)
281
    case null
282
 
283
    static public func == (lhs: Index, rhs: Index) -> Bool {
284
        switch (lhs, rhs) {
285
        case (.array(let left), .array(let right)):           return left == right
286
        case (.dictionary(let left), .dictionary(let right)): return left == right
287
        case (.null, .null):                                  return true
288
        default:                                              return false
289
        }
290
    }
291
 
292
    static public func < (lhs: Index, rhs: Index) -> Bool {
293
        switch (lhs, rhs) {
294
        case (.array(let left), .array(let right)):           return left < right
295
        case (.dictionary(let left), .dictionary(let right)): return left < right
296
        default:                                              return false
297
        }
298
    }
299
}
300
 
301
public typealias JSONIndex = Index<JSON>
302
public typealias JSONRawIndex = Index<Any>
303
 
304
extension JSON: Swift.Collection {
305
 
306
    public typealias Index = JSONRawIndex
307
 
308
    public var startIndex: Index {
309
        switch type {
310
        case .array:      return .array(rawArray.startIndex)
311
        case .dictionary: return .dictionary(rawDictionary.startIndex)
312
        default:          return .null
313
        }
314
    }
315
 
316
    public var endIndex: Index {
317
        switch type {
318
        case .array:      return .array(rawArray.endIndex)
319
        case .dictionary: return .dictionary(rawDictionary.endIndex)
320
        default:          return .null
321
        }
322
    }
323
 
324
    public func index(after i: Index) -> Index {
325
        switch i {
326
        case .array(let idx):      return .array(rawArray.index(after: idx))
327
        case .dictionary(let idx): return .dictionary(rawDictionary.index(after: idx))
328
        default:                   return .null
329
        }
330
    }
331
 
332
    public subscript (position: Index) -> (String, JSON) {
333
        switch position {
334
        case .array(let idx):      return (String(idx), JSON(rawArray[idx]))
335
        case .dictionary(let idx): return (rawDictionary[idx].key, JSON(rawDictionary[idx].value))
336
        default:                   return ("", JSON.null)
337
        }
338
    }
339
}
340
 
341
// MARK: - Subscript
342
 
343
/**
344
 *  To mark both String and Int can be used in subscript.
345
 */
346
public enum JSONKey {
347
    case index(Int)
348
    case key(String)
349
}
350
 
351
public protocol JSONSubscriptType {
352
    var jsonKey: JSONKey { get }
353
}
354
 
355
extension Int: JSONSubscriptType {
356
    public var jsonKey: JSONKey {
357
        return JSONKey.index(self)
358
    }
359
}
360
 
361
extension String: JSONSubscriptType {
362
    public var jsonKey: JSONKey {
363
        return JSONKey.key(self)
364
    }
365
}
366
 
367
extension JSON {
368
 
369
    /// If `type` is `.array`, return json whose object is `array[index]`, otherwise return null json with error.
370
    fileprivate subscript(index index: Int) -> JSON {
371
        get {
372
            if type != .array {
373
                var r = JSON.null
374
                r.error = self.error ?? SwiftyJSONError.wrongType
375
                return r
376
            } else if rawArray.indices.contains(index) {
377
                return JSON(rawArray[index])
378
            } else {
379
                var r = JSON.null
380
                r.error = SwiftyJSONError.indexOutOfBounds
381
                return r
382
            }
383
        }
384
        set {
385
            if type == .array &&
386
                rawArray.indices.contains(index) &&
387
                newValue.error == nil {
388
                rawArray[index] = newValue.object
389
            }
390
        }
391
    }
392
 
393
    /// If `type` is `.dictionary`, return json whose object is `dictionary[key]` , otherwise return null json with error.
394
    fileprivate subscript(key key: String) -> JSON {
395
        get {
396
            var r = JSON.null
397
            if type == .dictionary {
398
                if let o = rawDictionary[key] {
399
                    r = JSON(o)
400
                } else {
401
                    r.error = SwiftyJSONError.notExist
402
                }
403
            } else {
404
                r.error = self.error ?? SwiftyJSONError.wrongType
405
            }
406
            return r
407
        }
408
        set {
409
            if type == .dictionary && newValue.error == nil {
410
                rawDictionary[key] = newValue.object
411
            }
412
        }
413
    }
414
 
415
    /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`,  return `subscript(key:)`.
416
    fileprivate subscript(sub sub: JSONSubscriptType) -> JSON {
417
        get {
418
            switch sub.jsonKey {
419
            case .index(let index): return self[index: index]
420
            case .key(let key):     return self[key: key]
421
            }
422
        }
423
        set {
424
            switch sub.jsonKey {
425
            case .index(let index): self[index: index] = newValue
426
            case .key(let key):     self[key: key] = newValue
427
            }
428
        }
429
    }
430
 
431
	/**
432
	 Find a json in the complex data structures by using array of Int and/or String as path.
433
 
434
	 Example:
435
 
436
	 ```
437
	 let json = JSON[data]
438
	 let path = [9,"list","person","name"]
439
	 let name = json[path]
440
	 ```
441
 
442
	 The same as: let name = json[9]["list"]["person"]["name"]
443
 
444
	 - parameter path: The target json's path.
445
 
446
	 - returns: Return a json found by the path or a null json with error
447
	 */
448
    public subscript(path: [JSONSubscriptType]) -> JSON {
449
        get {
450
            return path.reduce(self) { $0[sub: $1] }
451
        }
452
        set {
453
            switch path.count {
454
            case 0: return
455
            case 1: self[sub:path[0]].object = newValue.object
456
            default:
457
                var aPath = path
458
                aPath.remove(at: 0)
459
                var nextJSON = self[sub: path[0]]
460
                nextJSON[aPath] = newValue
461
                self[sub: path[0]] = nextJSON
462
            }
463
        }
464
    }
465
 
466
    /**
467
     Find a json in the complex data structures by using array of Int and/or String as path.
468
 
469
     - parameter path: The target json's path. Example:
470
 
471
     let name = json[9,"list","person","name"]
472
 
473
     The same as: let name = json[9]["list"]["person"]["name"]
474
 
475
     - returns: Return a json found by the path or a null json with error
476
     */
477
    public subscript(path: JSONSubscriptType...) -> JSON {
478
        get {
479
            return self[path]
480
        }
481
        set {
482
            self[path] = newValue
483
        }
484
    }
485
}
486
 
487
// MARK: - LiteralConvertible
488
 
489
extension JSON: Swift.ExpressibleByStringLiteral {
490
 
491
    public init(stringLiteral value: StringLiteralType) {
492
        self.init(value)
493
    }
494
 
495
    public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
496
        self.init(value)
497
    }
498
 
499
    public init(unicodeScalarLiteral value: StringLiteralType) {
500
        self.init(value)
501
    }
502
}
503
 
504
extension JSON: Swift.ExpressibleByIntegerLiteral {
505
 
506
    public init(integerLiteral value: IntegerLiteralType) {
507
        self.init(value)
508
    }
509
}
510
 
511
extension JSON: Swift.ExpressibleByBooleanLiteral {
512
 
513
    public init(booleanLiteral value: BooleanLiteralType) {
514
        self.init(value)
515
    }
516
}
517
 
518
extension JSON: Swift.ExpressibleByFloatLiteral {
519
 
520
    public init(floatLiteral value: FloatLiteralType) {
521
        self.init(value)
522
    }
523
}
524
 
525
extension JSON: Swift.ExpressibleByDictionaryLiteral {
526
    public init(dictionaryLiteral elements: (String, Any)...) {
527
        let dictionary = elements.reduce(into: [String: Any](), { $0[$1.0] = $1.1})
528
        self.init(dictionary)
529
    }
530
}
531
 
532
extension JSON: Swift.ExpressibleByArrayLiteral {
533
 
534
    public init(arrayLiteral elements: Any...) {
535
        self.init(elements)
536
    }
537
}
538
 
539
// MARK: - Raw
540
 
541
extension JSON: Swift.RawRepresentable {
542
 
543
    public init?(rawValue: Any) {
544
        if JSON(rawValue).type == .unknown {
545
            return nil
546
        } else {
547
            self.init(rawValue)
548
        }
549
    }
550
 
551
    public var rawValue: Any {
552
        return object
553
    }
554
 
555
    public func rawData(options opt: JSONSerialization.WritingOptions = JSONSerialization.WritingOptions(rawValue: 0)) throws -> Data {
556
        guard JSONSerialization.isValidJSONObject(object) else {
557
            throw SwiftyJSONError.invalidJSON
558
        }
559
 
560
        return try JSONSerialization.data(withJSONObject: object, options: opt)
561
	}
562
 
563
	public func rawString(_ encoding: String.Encoding = .utf8, options opt: JSONSerialization.WritingOptions = .prettyPrinted) -> String? {
564
		do {
565
			return try _rawString(encoding, options: [.jsonSerialization: opt])
566
		} catch {
567
			print("Could not serialize object to JSON because:", error.localizedDescription)
568
			return nil
569
		}
570
	}
571
 
572
	public func rawString(_ options: [writingOptionsKeys: Any]) -> String? {
573
		let encoding = options[.encoding] as? String.Encoding ?? String.Encoding.utf8
574
		let maxObjectDepth = options[.maxObjextDepth] as? Int ?? 10
575
		do {
576
			return try _rawString(encoding, options: options, maxObjectDepth: maxObjectDepth)
577
		} catch {
578
			print("Could not serialize object to JSON because:", error.localizedDescription)
579
			return nil
580
		}
581
	}
582
 
583
	fileprivate func _rawString(_ encoding: String.Encoding = .utf8, options: [writingOptionsKeys: Any], maxObjectDepth: Int = 10) throws -> String? {
584
        guard maxObjectDepth > 0 else { throw SwiftyJSONError.invalidJSON }
585
        switch type {
586
        case .dictionary:
587
			do {
588
				if !(options[.castNilToNSNull] as? Bool ?? false) {
589
					let jsonOption = options[.jsonSerialization] as? JSONSerialization.WritingOptions ?? JSONSerialization.WritingOptions.prettyPrinted
590
					let data = try rawData(options: jsonOption)
591
					return String(data: data, encoding: encoding)
592
				}
593
 
594
				guard let dict = object as? [String: Any?] else {
595
					return nil
596
				}
597
				let body = try dict.keys.map { key throws -> String in
598
					guard let value = dict[key] else {
599
						return "\"\(key)\": null"
600
					}
601
					guard let unwrappedValue = value else {
602
						return "\"\(key)\": null"
603
					}
604
 
605
					let nestedValue = JSON(unwrappedValue)
606
					guard let nestedString = try nestedValue._rawString(encoding, options: options, maxObjectDepth: maxObjectDepth - 1) else {
607
						throw SwiftyJSONError.elementTooDeep
608
					}
609
					if nestedValue.type == .string {
610
						return "\"\(key)\": \"\(nestedString.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\"", with: "\\\""))\""
611
					} else {
612
						return "\"\(key)\": \(nestedString)"
613
					}
614
				}
615
 
616
				return "{\(body.joined(separator: ","))}"
617
			} catch _ {
618
				return nil
619
			}
620
        case .array:
621
            do {
622
				if !(options[.castNilToNSNull] as? Bool ?? false) {
623
					let jsonOption = options[.jsonSerialization] as? JSONSerialization.WritingOptions ?? JSONSerialization.WritingOptions.prettyPrinted
624
					let data = try rawData(options: jsonOption)
625
					return String(data: data, encoding: encoding)
626
				}
627
 
628
                guard let array = object as? [Any?] else {
629
                    return nil
630
                }
631
                let body = try array.map { value throws -> String in
632
                    guard let unwrappedValue = value else {
633
                        return "null"
634
                    }
635
 
636
                    let nestedValue = JSON(unwrappedValue)
637
                    guard let nestedString = try nestedValue._rawString(encoding, options: options, maxObjectDepth: maxObjectDepth - 1) else {
638
                        throw SwiftyJSONError.invalidJSON
639
                    }
640
                    if nestedValue.type == .string {
641
                        return "\"\(nestedString.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\"", with: "\\\""))\""
642
                    } else {
643
                        return nestedString
644
                    }
645
                }
646
 
647
                return "[\(body.joined(separator: ","))]"
648
            } catch _ {
649
                return nil
650
            }
651
        case .string: return rawString
652
        case .number: return rawNumber.stringValue
653
        case .bool:   return rawBool.description
654
        case .null:   return "null"
655
        default:      return nil
656
        }
657
    }
658
}
659
 
660
// MARK: - Printable, DebugPrintable
661
 
662
extension JSON: Swift.CustomStringConvertible, Swift.CustomDebugStringConvertible {
663
 
664
    public var description: String {
665
        return rawString(options: .prettyPrinted) ?? "unknown"
666
    }
667
 
668
    public var debugDescription: String {
669
        return description
670
    }
671
}
672
 
673
// MARK: - Array
674
 
675
extension JSON {
676
 
677
    //Optional [JSON]
678
    public var array: [JSON]? {
679
        return type == .array ? rawArray.map { JSON($0) } : nil
680
    }
681
 
682
    //Non-optional [JSON]
683
    public var arrayValue: [JSON] {
684
        return self.array ?? []
685
    }
686
 
687
    //Optional [Any]
688
    public var arrayObject: [Any]? {
689
        get {
690
            switch type {
691
            case .array: return rawArray
692
            default:     return nil
693
            }
694
        }
695
        set {
696
            self.object = newValue ?? NSNull()
697
        }
698
    }
699
}
700
 
701
// MARK: - Dictionary
702
 
703
extension JSON {
704
 
705
    //Optional [String : JSON]
706
    public var dictionary: [String: JSON]? {
707
        if type == .dictionary {
708
            var d = [String: JSON](minimumCapacity: rawDictionary.count)
709
            rawDictionary.forEach { pair in
710
                d[pair.key] = JSON(pair.value)
711
            }
712
            return d
713
        } else {
714
            return nil
715
        }
716
    }
717
 
718
    //Non-optional [String : JSON]
719
    public var dictionaryValue: [String: JSON] {
720
        return dictionary ?? [:]
721
    }
722
 
723
    //Optional [String : Any]
724
 
725
    public var dictionaryObject: [String: Any]? {
726
        get {
727
            switch type {
728
            case .dictionary: return rawDictionary
729
            default:          return nil
730
            }
731
        }
732
        set {
733
            object = newValue ?? NSNull()
734
        }
735
    }
736
}
737
 
738
// MARK: - Bool
739
 
740
extension JSON { // : Swift.Bool
741
 
742
    //Optional bool
743
    public var bool: Bool? {
744
        get {
745
            switch type {
746
            case .bool: return rawBool
747
            default:    return nil
748
            }
749
        }
750
        set {
751
            object = newValue ?? NSNull()
752
        }
753
    }
754
 
755
    //Non-optional bool
756
    public var boolValue: Bool {
757
        get {
758
            switch type {
759
            case .bool:   return rawBool
760
            case .number: return rawNumber.boolValue
761
            case .string: return ["true", "y", "t", "yes", "1"].contains { rawString.caseInsensitiveCompare($0) == .orderedSame }
762
            default:      return false
763
            }
764
        }
765
        set {
766
            object = newValue
767
        }
768
    }
769
}
770
 
771
// MARK: - String
772
 
773
extension JSON {
774
 
775
    //Optional string
776
    public var string: String? {
777
        get {
778
            switch type {
779
            case .string: return object as? String
780
            default:      return nil
781
            }
782
        }
783
        set {
784
            object = newValue ?? NSNull()
785
        }
786
    }
787
 
788
    //Non-optional string
789
    public var stringValue: String {
790
        get {
791
            switch type {
792
            case .string: return object as? String ?? ""
793
            case .number: return rawNumber.stringValue
794
            case .bool:   return (object as? Bool).map { String($0) } ?? ""
795
            default:      return ""
796
            }
797
        }
798
        set {
799
            object = newValue
800
        }
801
    }
802
}
803
 
804
// MARK: - Number
805
 
806
extension JSON {
807
 
808
    //Optional number
809
    public var number: NSNumber? {
810
        get {
811
            switch type {
812
            case .number: return rawNumber
813
            case .bool:   return NSNumber(value: rawBool ? 1 : 0)
814
            default:      return nil
815
            }
816
        }
817
        set {
818
            object = newValue ?? NSNull()
819
        }
820
    }
821
 
822
    //Non-optional number
823
    public var numberValue: NSNumber {
824
        get {
825
            switch type {
826
            case .string:
827
                let decimal = NSDecimalNumber(string: object as? String)
828
                return decimal == .notANumber ? .zero : decimal
829
            case .number: return object as? NSNumber ?? NSNumber(value: 0)
830
            case .bool: return NSNumber(value: rawBool ? 1 : 0)
831
            default: return NSNumber(value: 0.0)
832
            }
833
        }
834
        set {
835
            object = newValue
836
        }
837
    }
838
}
839
 
840
// MARK: - Null
841
 
842
extension JSON {
843
 
844
    public var null: NSNull? {
845
        set {
846
            object = NSNull()
847
        }
848
        get {
849
            switch type {
850
            case .null: return rawNull
851
            default:    return nil
852
            }
853
        }
854
    }
855
    public func exists() -> Bool {
856
        if let errorValue = error, (400...1000).contains(errorValue.errorCode) {
857
            return false
858
        }
859
        return true
860
    }
861
}
862
 
863
// MARK: - URL
864
 
865
extension JSON {
866
 
867
    //Optional URL
868
    public var url: URL? {
869
        get {
870
            switch type {
871
            case .string:
872
                // Check for existing percent escapes first to prevent double-escaping of % character
873
                if rawString.range(of: "%[0-9A-Fa-f]{2}", options: .regularExpression, range: nil, locale: nil) != nil {
874
                    return Foundation.URL(string: rawString)
875
                } else if let encodedString_ = rawString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) {
876
                    // We have to use `Foundation.URL` otherwise it conflicts with the variable name.
877
                    return Foundation.URL(string: encodedString_)
878
                } else {
879
                    return nil
880
                }
881
            default:
882
                return nil
883
            }
884
        }
885
        set {
886
            object = newValue?.absoluteString ?? NSNull()
887
        }
888
    }
889
}
890
 
891
// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
892
 
893
extension JSON {
894
 
895
    public var double: Double? {
896
        get {
897
            return number?.doubleValue
898
        }
899
        set {
900
            if let newValue = newValue {
901
                object = NSNumber(value: newValue)
902
            } else {
903
                object = NSNull()
904
            }
905
        }
906
    }
907
 
908
    public var doubleValue: Double {
909
        get {
910
            return numberValue.doubleValue
911
        }
912
        set {
913
            object = NSNumber(value: newValue)
914
        }
915
    }
916
 
917
    public var float: Float? {
918
        get {
919
            return number?.floatValue
920
        }
921
        set {
922
            if let newValue = newValue {
923
                object = NSNumber(value: newValue)
924
            } else {
925
                object = NSNull()
926
            }
927
        }
928
    }
929
 
930
    public var floatValue: Float {
931
        get {
932
            return numberValue.floatValue
933
        }
934
        set {
935
            object = NSNumber(value: newValue)
936
        }
937
    }
938
 
939
    public var int: Int? {
940
        get {
941
            return number?.intValue
942
        }
943
        set {
944
            if let newValue = newValue {
945
                object = NSNumber(value: newValue)
946
            } else {
947
                object = NSNull()
948
            }
949
        }
950
    }
951
 
952
    public var intValue: Int {
953
        get {
954
            return numberValue.intValue
955
        }
956
        set {
957
            object = NSNumber(value: newValue)
958
        }
959
    }
960
 
961
    public var uInt: UInt? {
962
        get {
963
            return number?.uintValue
964
        }
965
        set {
966
            if let newValue = newValue {
967
                object = NSNumber(value: newValue)
968
            } else {
969
                object = NSNull()
970
            }
971
        }
972
    }
973
 
974
    public var uIntValue: UInt {
975
        get {
976
            return numberValue.uintValue
977
        }
978
        set {
979
            object = NSNumber(value: newValue)
980
        }
981
    }
982
 
983
    public var int8: Int8? {
984
        get {
985
            return number?.int8Value
986
        }
987
        set {
988
            if let newValue = newValue {
989
                object = NSNumber(value: Int(newValue))
990
            } else {
991
                object =  NSNull()
992
            }
993
        }
994
    }
995
 
996
    public var int8Value: Int8 {
997
        get {
998
            return numberValue.int8Value
999
        }
1000
        set {
1001
            object = NSNumber(value: Int(newValue))
1002
        }
1003
    }
1004
 
1005
    public var uInt8: UInt8? {
1006
        get {
1007
            return number?.uint8Value
1008
        }
1009
        set {
1010
            if let newValue = newValue {
1011
                object = NSNumber(value: newValue)
1012
            } else {
1013
                object =  NSNull()
1014
            }
1015
        }
1016
    }
1017
 
1018
    public var uInt8Value: UInt8 {
1019
        get {
1020
            return numberValue.uint8Value
1021
        }
1022
        set {
1023
            object = NSNumber(value: newValue)
1024
        }
1025
    }
1026
 
1027
    public var int16: Int16? {
1028
        get {
1029
            return number?.int16Value
1030
        }
1031
        set {
1032
            if let newValue = newValue {
1033
                object = NSNumber(value: newValue)
1034
            } else {
1035
                object =  NSNull()
1036
            }
1037
        }
1038
    }
1039
 
1040
    public var int16Value: Int16 {
1041
        get {
1042
            return numberValue.int16Value
1043
        }
1044
        set {
1045
            object = NSNumber(value: newValue)
1046
        }
1047
    }
1048
 
1049
    public var uInt16: UInt16? {
1050
        get {
1051
            return number?.uint16Value
1052
        }
1053
        set {
1054
            if let newValue = newValue {
1055
                object = NSNumber(value: newValue)
1056
            } else {
1057
                object =  NSNull()
1058
            }
1059
        }
1060
    }
1061
 
1062
    public var uInt16Value: UInt16 {
1063
        get {
1064
            return numberValue.uint16Value
1065
        }
1066
        set {
1067
            object = NSNumber(value: newValue)
1068
        }
1069
    }
1070
 
1071
    public var int32: Int32? {
1072
        get {
1073
            return number?.int32Value
1074
        }
1075
        set {
1076
            if let newValue = newValue {
1077
                object = NSNumber(value: newValue)
1078
            } else {
1079
                object =  NSNull()
1080
            }
1081
        }
1082
    }
1083
 
1084
    public var int32Value: Int32 {
1085
        get {
1086
            return numberValue.int32Value
1087
        }
1088
        set {
1089
            object = NSNumber(value: newValue)
1090
        }
1091
    }
1092
 
1093
    public var uInt32: UInt32? {
1094
        get {
1095
            return number?.uint32Value
1096
        }
1097
        set {
1098
            if let newValue = newValue {
1099
                object = NSNumber(value: newValue)
1100
            } else {
1101
                object =  NSNull()
1102
            }
1103
        }
1104
    }
1105
 
1106
    public var uInt32Value: UInt32 {
1107
        get {
1108
            return numberValue.uint32Value
1109
        }
1110
        set {
1111
            object = NSNumber(value: newValue)
1112
        }
1113
    }
1114
 
1115
    public var int64: Int64? {
1116
        get {
1117
            return number?.int64Value
1118
        }
1119
        set {
1120
            if let newValue = newValue {
1121
                object = NSNumber(value: newValue)
1122
            } else {
1123
                object =  NSNull()
1124
            }
1125
        }
1126
    }
1127
 
1128
    public var int64Value: Int64 {
1129
        get {
1130
            return numberValue.int64Value
1131
        }
1132
        set {
1133
            object = NSNumber(value: newValue)
1134
        }
1135
    }
1136
 
1137
    public var uInt64: UInt64? {
1138
        get {
1139
            return number?.uint64Value
1140
        }
1141
        set {
1142
            if let newValue = newValue {
1143
                object = NSNumber(value: newValue)
1144
            } else {
1145
                object =  NSNull()
1146
            }
1147
        }
1148
    }
1149
 
1150
    public var uInt64Value: UInt64 {
1151
        get {
1152
            return numberValue.uint64Value
1153
        }
1154
        set {
1155
            object = NSNumber(value: newValue)
1156
        }
1157
    }
1158
}
1159
 
1160
// MARK: - Comparable
1161
 
1162
extension JSON: Swift.Comparable {}
1163
 
1164
public func == (lhs: JSON, rhs: JSON) -> Bool {
1165
 
1166
    switch (lhs.type, rhs.type) {
1167
    case (.number, .number): return lhs.rawNumber == rhs.rawNumber
1168
    case (.string, .string): return lhs.rawString == rhs.rawString
1169
    case (.bool, .bool):     return lhs.rawBool == rhs.rawBool
1170
    case (.array, .array):   return lhs.rawArray as NSArray == rhs.rawArray as NSArray
1171
    case (.dictionary, .dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
1172
    case (.null, .null):     return true
1173
    default:                 return false
1174
    }
1175
}
1176
 
1177
public func <= (lhs: JSON, rhs: JSON) -> Bool {
1178
 
1179
    switch (lhs.type, rhs.type) {
1180
    case (.number, .number): return lhs.rawNumber <= rhs.rawNumber
1181
    case (.string, .string): return lhs.rawString <= rhs.rawString
1182
    case (.bool, .bool):     return lhs.rawBool == rhs.rawBool
1183
    case (.array, .array):   return lhs.rawArray as NSArray == rhs.rawArray as NSArray
1184
    case (.dictionary, .dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
1185
    case (.null, .null):     return true
1186
    default:                 return false
1187
    }
1188
}
1189
 
1190
public func >= (lhs: JSON, rhs: JSON) -> Bool {
1191
 
1192
    switch (lhs.type, rhs.type) {
1193
    case (.number, .number): return lhs.rawNumber >= rhs.rawNumber
1194
    case (.string, .string): return lhs.rawString >= rhs.rawString
1195
    case (.bool, .bool):     return lhs.rawBool == rhs.rawBool
1196
    case (.array, .array):   return lhs.rawArray as NSArray == rhs.rawArray as NSArray
1197
    case (.dictionary, .dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
1198
    case (.null, .null):     return true
1199
    default:                 return false
1200
    }
1201
}
1202
 
1203
public func > (lhs: JSON, rhs: JSON) -> Bool {
1204
 
1205
    switch (lhs.type, rhs.type) {
1206
    case (.number, .number): return lhs.rawNumber > rhs.rawNumber
1207
    case (.string, .string): return lhs.rawString > rhs.rawString
1208
    default:                 return false
1209
    }
1210
}
1211
 
1212
public func < (lhs: JSON, rhs: JSON) -> Bool {
1213
 
1214
    switch (lhs.type, rhs.type) {
1215
    case (.number, .number): return lhs.rawNumber < rhs.rawNumber
1216
    case (.string, .string): return lhs.rawString < rhs.rawString
1217
    default:                 return false
1218
    }
1219
}
1220
 
1221
private let trueNumber = NSNumber(value: true)
1222
private let falseNumber = NSNumber(value: false)
1223
private let trueObjCType = String(cString: trueNumber.objCType)
1224
private let falseObjCType = String(cString: falseNumber.objCType)
1225
 
1226
// MARK: - NSNumber: Comparable
1227
 
1228
extension NSNumber {
1229
    fileprivate var isBool: Bool {
1230
        let objCType = String(cString: self.objCType)
1231
        if (self.compare(trueNumber) == .orderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == .orderedSame && objCType == falseObjCType) {
1232
            return true
1233
        } else {
1234
            return false
1235
        }
1236
    }
1237
}
1238
 
1239
func == (lhs: NSNumber, rhs: NSNumber) -> Bool {
1240
    switch (lhs.isBool, rhs.isBool) {
1241
    case (false, true): return false
1242
    case (true, false): return false
1243
    default:            return lhs.compare(rhs) == .orderedSame
1244
    }
1245
}
1246
 
1247
func != (lhs: NSNumber, rhs: NSNumber) -> Bool {
1248
    return !(lhs == rhs)
1249
}
1250
 
1251
func < (lhs: NSNumber, rhs: NSNumber) -> Bool {
1252
 
1253
    switch (lhs.isBool, rhs.isBool) {
1254
    case (false, true): return false
1255
    case (true, false): return false
1256
    default:            return lhs.compare(rhs) == .orderedAscending
1257
    }
1258
}
1259
 
1260
func > (lhs: NSNumber, rhs: NSNumber) -> Bool {
1261
 
1262
    switch (lhs.isBool, rhs.isBool) {
1263
    case (false, true): return false
1264
    case (true, false): return false
1265
    default:            return lhs.compare(rhs) == ComparisonResult.orderedDescending
1266
    }
1267
}
1268
 
1269
func <= (lhs: NSNumber, rhs: NSNumber) -> Bool {
1270
 
1271
    switch (lhs.isBool, rhs.isBool) {
1272
    case (false, true): return false
1273
    case (true, false): return false
1274
    default:            return lhs.compare(rhs) != .orderedDescending
1275
    }
1276
}
1277
 
1278
func >= (lhs: NSNumber, rhs: NSNumber) -> Bool {
1279
 
1280
    switch (lhs.isBool, rhs.isBool) {
1281
    case (false, true): return false
1282
    case (true, false): return false
1283
    default:            return lhs.compare(rhs) != .orderedAscending
1284
    }
1285
}
1286
 
1287
public enum writingOptionsKeys {
1288
	case jsonSerialization
1289
	case castNilToNSNull
1290
	case maxObjextDepth
1291
	case encoding
1292
}
1293
 
1294
// MARK: - JSON: Codable
1295
extension JSON: Codable {
1296
    private static var codableTypes: [Codable.Type] {
1297
        return [
1298
            Bool.self,
1299
            Int.self,
1300
            Int8.self,
1301
            Int16.self,
1302
            Int32.self,
1303
            Int64.self,
1304
            UInt.self,
1305
            UInt8.self,
1306
            UInt16.self,
1307
            UInt32.self,
1308
            UInt64.self,
1309
            Double.self,
1310
            String.self,
1311
            [JSON].self,
1312
            [String: JSON].self
1313
        ]
1314
    }
1315
    public init(from decoder: Decoder) throws {
1316
        var object: Any?
1317
 
1318
        if let container = try? decoder.singleValueContainer(), !container.decodeNil() {
1319
            for type in JSON.codableTypes {
1320
                if object != nil {
1321
                    break
1322
                }
1323
                // try to decode value
1324
                switch type {
1325
                case let boolType as Bool.Type:
1326
                    object = try? container.decode(boolType)
1327
                case let intType as Int.Type:
1328
                    object = try? container.decode(intType)
1329
                case let int8Type as Int8.Type:
1330
                    object = try? container.decode(int8Type)
1331
                case let int32Type as Int32.Type:
1332
                    object = try? container.decode(int32Type)
1333
                case let int64Type as Int64.Type:
1334
                    object = try? container.decode(int64Type)
1335
                case let uintType as UInt.Type:
1336
                    object = try? container.decode(uintType)
1337
                case let uint8Type as UInt8.Type:
1338
                    object = try? container.decode(uint8Type)
1339
                case let uint16Type as UInt16.Type:
1340
                    object = try? container.decode(uint16Type)
1341
                case let uint32Type as UInt32.Type:
1342
                    object = try? container.decode(uint32Type)
1343
                case let uint64Type as UInt64.Type:
1344
                    object = try? container.decode(uint64Type)
1345
                case let doubleType as Double.Type:
1346
                    object = try? container.decode(doubleType)
1347
                case let stringType as String.Type:
1348
                    object = try? container.decode(stringType)
1349
                case let jsonValueArrayType as [JSON].Type:
1350
                    object = try? container.decode(jsonValueArrayType)
1351
                case let jsonValueDictType as [String: JSON].Type:
1352
                    object = try? container.decode(jsonValueDictType)
1353
                default:
1354
                    break
1355
                }
1356
            }
1357
        }
1358
        self.init(object ?? NSNull())
1359
    }
1360
    public func encode(to encoder: Encoder) throws {
1361
        var container = encoder.singleValueContainer()
1362
        if object is NSNull {
1363
            try container.encodeNil()
1364
            return
1365
        }
1366
        switch object {
1367
        case let intValue as Int:
1368
            try container.encode(intValue)
1369
        case let int8Value as Int8:
1370
            try container.encode(int8Value)
1371
        case let int32Value as Int32:
1372
            try container.encode(int32Value)
1373
        case let int64Value as Int64:
1374
            try container.encode(int64Value)
1375
        case let uintValue as UInt:
1376
            try container.encode(uintValue)
1377
        case let uint8Value as UInt8:
1378
            try container.encode(uint8Value)
1379
        case let uint16Value as UInt16:
1380
            try container.encode(uint16Value)
1381
        case let uint32Value as UInt32:
1382
            try container.encode(uint32Value)
1383
        case let uint64Value as UInt64:
1384
            try container.encode(uint64Value)
1385
        case let doubleValue as Double:
1386
            try container.encode(doubleValue)
1387
        case let boolValue as Bool:
1388
            try container.encode(boolValue)
1389
        case let stringValue as String:
1390
            try container.encode(stringValue)
1391
        case is [Any]:
1392
            let jsonValueArray = array ?? []
1393
            try container.encode(jsonValueArray)
1394
        case is [String: Any]:
1395
            let jsonValueDictValue = dictionary ?? [:]
1396
            try container.encode(jsonValueDictValue)
1397
        default:
1398
            break
1399
        }
1400
    }
1401
}