2 // String+OAuthSwift.swift
5 // Created by Dongri Jin on 6/21/14.
6 // Copyright (c) 2014 Dongri Jin. All rights reserved.
13 var parametersFromQueryString: [String: String] {
14 return dictionaryBySplitting("&", keyValueSeparator: "=")
17 /// Encodes url string making it ready to be passed as a query parameter. This encodes pretty much everything apart from
18 /// alphanumerics and a few other characters compared to standard query encoding.
19 var urlEncoded: String {
20 let customAllowedSet = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~")
21 return self.addingPercentEncoding(withAllowedCharacters: customAllowedSet)!
24 var urlQueryEncoded: String? {
25 return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
28 /// Returns new url query string by appending query parameter encoding it first, if specified.
29 func urlQueryByAppending(parameter name: String, value: String, encode: Bool = true, _ encodeError: ((String, String) -> Void)? = nil) -> String? {
32 } else if let value = encode ? value.urlQueryEncoded : value {
33 return "\(self)\(self.isEmpty ? "" : "&")\(name)=\(value)"
35 encodeError?(name, value)
40 /// Returns new url string by appending query string at the end.
41 func urlByAppending(query: String) -> String {
42 return "\(self)\(self.contains("?") ? "&" : "?")\(query)"
45 fileprivate func dictionaryBySplitting(_ elementSeparator: String, keyValueSeparator: String) -> [String: String] {
48 if hasPrefix(elementSeparator) {
49 string = String(dropFirst(1))
52 var parameters = [String: String]()
54 let scanner = Scanner(string: string)
59 while !scanner.isAtEnd {
61 scanner.scanUpTo(keyValueSeparator, into: &key)
62 scanner.scanString(keyValueSeparator, into: nil)
65 scanner.scanUpTo(elementSeparator, into: &value)
66 scanner.scanString(elementSeparator, into: nil)
68 if let key = key as String? {
69 if let value = value as String? {
70 if key.contains(elementSeparator) {
71 var keys = key.components(separatedBy: elementSeparator)
72 if let key = keys.popLast() {
73 parameters.updateValue(value, forKey: String(key))
76 parameters.updateValue("", forKey: flag)
79 parameters.updateValue(value, forKey: key)
82 parameters.updateValue("", forKey: key)
90 public var headerDictionary: OAuthSwift.Headers {
91 return dictionaryBySplitting(",", keyValueSeparator: "=")
94 var safeStringByRemovingPercentEncoding: String {
95 return self.removingPercentEncoding ?? self
98 mutating func dropLast() {
99 self.remove(at: self.index(before: self.endIndex))
102 subscript (bounds: CountableClosedRange<Int>) -> String {
103 let start = index(startIndex, offsetBy: bounds.lowerBound)
104 let end = index(startIndex, offsetBy: bounds.upperBound)
105 return String(self[start...end])
108 subscript (bounds: CountableRange<Int>) -> String {
109 let start = index(startIndex, offsetBy: bounds.lowerBound)
110 let end = index(startIndex, offsetBy: bounds.upperBound)
111 return String(self[start..<end])
115 extension String.Encoding {
117 var charset: String {
118 let charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.rawValue))
119 // swiftlint:disable:next force_cast
120 return charset! as String