Skip to content

Commit 13071fb

Browse files
committed
Restore query string utility classes
1 parent 4c5c9af commit 13071fb

File tree

5 files changed

+216
-0
lines changed

5 files changed

+216
-0
lines changed

Authenticator.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
8B0028B511EB75920092DE18 /* OTPScannerOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B0028B411EB75920092DE18 /* OTPScannerOverlayView.m */; };
1414
8BF23A7213D4EF7000F3FD82 /* UIColor+OTP.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF23A7113D4EF7000F3FD82 /* UIColor+OTP.m */; };
1515
C9044FD61824CDE7002C3C3F /* OTPBase32Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = C9044FD51824CDE7002C3C3F /* OTPBase32Tests.m */; };
16+
C9044FD91824E05E002C3C3F /* NSString+PercentEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = C9044FD81824E05E002C3C3F /* NSString+PercentEncoding.m */; };
17+
C9044FDC1824E711002C3C3F /* NSDictionary+QueryString.m in Sources */ = {isa = PBXBuildFile; fileRef = C9044FDB1824E711002C3C3F /* NSDictionary+QueryString.m */; };
1618
C940A981183EEFA300F7D04A /* OTPTokenGenerationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C940A980183EEFA300F7D04A /* OTPTokenGenerationTests.m */; };
1719
C958CC54183043A600DD47D0 /* OTPTokenSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C958CC53183043A600DD47D0 /* OTPTokenSerializationTests.m */; };
1820
C9745D0B17DA5861008B6E23 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = C9745D0A17DA5861008B6E23 /* UIAlertView+Blocks.m */; };
@@ -57,6 +59,10 @@
5759
8BF5147F118799AE005C936F /* Authenticator-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Authenticator-Info.plist"; sourceTree = "<group>"; };
5860
9B03839CF35E4014987A36CA /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
5961
C9044FD51824CDE7002C3C3F /* OTPBase32Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTPBase32Tests.m; sourceTree = "<group>"; };
62+
C9044FD71824E05E002C3C3F /* NSString+PercentEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+PercentEncoding.h"; sourceTree = "<group>"; };
63+
C9044FD81824E05E002C3C3F /* NSString+PercentEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+PercentEncoding.m"; sourceTree = "<group>"; };
64+
C9044FDA1824E711002C3C3F /* NSDictionary+QueryString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+QueryString.h"; sourceTree = "<group>"; };
65+
C9044FDB1824E711002C3C3F /* NSDictionary+QueryString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+QueryString.m"; sourceTree = "<group>"; };
6066
C940A980183EEFA300F7D04A /* OTPTokenGenerationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTPTokenGenerationTests.m; sourceTree = "<group>"; };
6167
C958CC53183043A600DD47D0 /* OTPTokenSerializationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTPTokenSerializationTests.m; sourceTree = "<group>"; };
6268
C959A63C190A69120042DEC0 /* Icon.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Icon.svg; sourceTree = "<group>"; };
@@ -239,6 +245,10 @@
239245
8BF23A7113D4EF7000F3FD82 /* UIColor+OTP.m */,
240246
C9745D0917DA5861008B6E23 /* UIAlertView+Blocks.h */,
241247
C9745D0A17DA5861008B6E23 /* UIAlertView+Blocks.m */,
248+
C9044FD71824E05E002C3C3F /* NSString+PercentEncoding.h */,
249+
C9044FD81824E05E002C3C3F /* NSString+PercentEncoding.m */,
250+
C9044FDA1824E711002C3C3F /* NSDictionary+QueryString.h */,
251+
C9044FDB1824E711002C3C3F /* NSDictionary+QueryString.m */,
242252
);
243253
name = Categories;
244254
sourceTree = "<group>";
@@ -432,6 +442,7 @@
432442
isa = PBXSourcesBuildPhase;
433443
buildActionMask = 2147483647;
434444
files = (
445+
C9044FD91824E05E002C3C3F /* NSString+PercentEncoding.m in Sources */,
435446
1D60589B0D05DD56006BFB54 /* main.m in Sources */,
436447
1D3623260D0F684500981E51 /* OTPAppDelegate.m in Sources */,
437448
C9D6C8461906CD54004F0E08 /* OTPTextFieldCell.m in Sources */,
@@ -446,6 +457,7 @@
446457
C99069D4180E07A100BAEF53 /* OTPTokenEntryViewController.m in Sources */,
447458
C9ABDACF17DD3CF500A86AB5 /* OTPTokenCell.m in Sources */,
448459
C9777A021908064500B4A7F5 /* OTPTokenEditViewController.m in Sources */,
460+
C9044FDC1824E711002C3C3F /* NSDictionary+QueryString.m in Sources */,
449461
);
450462
runOnlyForDeploymentPostprocessing = 0;
451463
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// NSDictionary+QueryString.h
3+
// Authenticator
4+
//
5+
// Copyright (c) 2013 Matt Rubin
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
//
24+
25+
@import Foundation;
26+
27+
28+
@interface NSDictionary (QueryString)
29+
30+
+ (instancetype)dictionaryWithQueryString:(NSString *)queryString;
31+
32+
- (NSString *)queryString;
33+
34+
@end
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// NSDictionary+QueryString.m
3+
// Authenticator
4+
//
5+
// Copyright (c) 2013 Matt Rubin
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
//
24+
25+
#import "NSDictionary+QueryString.h"
26+
#import "NSString+PercentEncoding.h"
27+
28+
29+
// For alternate implementations, see:
30+
// https://github.com/Singly/iOS-SDK/blob/master/SinglySDK/SinglySDK/NSDictionary%2BQueryString.m
31+
// https://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMNSDictionary%2BURLArguments.m
32+
33+
@implementation NSDictionary (QueryString)
34+
35+
// This method parses the arguments of a query string and returns a dictionary containing the
36+
// key-value pairs. All keys and values are returned as percent-decoded strings, and nested arguments
37+
// are not supported. Keys without arguments will not be included in the dictionary, and duplicate
38+
// keys will have their values overwritten.
39+
40+
+ (instancetype)dictionaryWithQueryString:(NSString *)queryString
41+
{
42+
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
43+
NSArray *pairs = [queryString componentsSeparatedByString:@"&"];
44+
45+
for (NSString *pair in pairs) {
46+
NSArray *elements = [pair componentsSeparatedByString:@"="];
47+
if (elements.count == 2) {
48+
NSString *key = [elements[0] percentDecodedString];
49+
NSString *value = [elements[1] percentDecodedString];
50+
dictionary[key] = value;
51+
}
52+
}
53+
54+
return dictionary;
55+
}
56+
57+
// This method returns a simple query-string-style representation of the dictionary.
58+
// All keys and values are expected to be strings, and if they are not then this method will attempt
59+
// to serialize them using the -description method. Keys and values are percent-encoded before being
60+
// added to the query string.
61+
62+
- (NSString *)queryString
63+
{
64+
NSMutableArray *keyValuePairs = [NSMutableArray arrayWithCapacity:self.count];
65+
for (id key in self) {
66+
id value = self[key];
67+
NSString *keyValueString = [NSString stringWithFormat:@"%@=%@", [[key description] percentEncodedString], [[value description] percentEncodedString]];
68+
[keyValuePairs addObject:keyValueString];
69+
}
70+
return [keyValuePairs componentsJoinedByString:@"&"];
71+
}
72+
73+
@end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// NSString+PercentEncoding.h
3+
// Authenticator
4+
//
5+
// Copyright (c) 2013 Matt Rubin
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
//
24+
25+
@import Foundation;
26+
27+
28+
@interface NSString (PercentEncoding)
29+
30+
- (NSString *)percentEncodedString;
31+
- (NSString *)percentDecodedString;
32+
33+
@end
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// NSString+PercentEncoding.m
3+
// Authenticator
4+
//
5+
// Copyright (c) 2013 Matt Rubin
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
8+
// this software and associated documentation files (the "Software"), to deal in
9+
// the Software without restriction, including without limitation the rights to
10+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11+
// the Software, and to permit persons to whom the Software is furnished to do so,
12+
// subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
//
24+
25+
#import "NSString+PercentEncoding.h"
26+
27+
28+
// For alternate implementations, see:
29+
// https://github.com/Singly/iOS-SDK/blob/master/SinglySDK/SinglySDK/NSString%2BURLEncoding.m
30+
// https://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMNSString%2BURLArguments.m
31+
32+
@implementation NSString (PercentEncoding)
33+
34+
// NSString's stringByAddingPercentEscapesUsingEncoding: doesn't percent-encode the reserved
35+
// characters defined in the URI specification ( https://tools.ietf.org/html/rfc3986#section-2.2 ).
36+
// This method escapes every reserved character to produce a string which is a valid argument for a
37+
// URL query string. (via http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/ )
38+
39+
- (NSString *)percentEncodedString
40+
{
41+
CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(NULL,
42+
(__bridge CFStringRef)(self),
43+
NULL,
44+
CFSTR(":/?#[]@!$&'()*+,;=%"),
45+
kCFStringEncodingUTF8);
46+
return CFBridgingRelease(escapedString);
47+
}
48+
49+
// This method unescapes all percent-encoded characters to convert a string from a URL into a human-
50+
// readable format. Prior to unescaping, it also converts all instances of '+' to spaces.
51+
52+
- (NSString *)percentDecodedString
53+
{
54+
// If a "+" exists in this string, it represents a space, since a literal "+" should have been converted to "%2B"
55+
NSString *stringWithSpaces = [self stringByReplacingOccurrencesOfString:@"+" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, self.length)];
56+
// Convert all percent-encoded characters back to their readable equivalents
57+
CFStringRef decodedString = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
58+
(__bridge CFStringRef)(stringWithSpaces),
59+
CFSTR(""),
60+
kCFStringEncodingUTF8);
61+
return CFBridgingRelease(decodedString);
62+
}
63+
64+
@end

0 commit comments

Comments
 (0)