Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Utility functions to decode URL-encoded strings.
  • Loading branch information
adamjernst committed Jan 24, 2012
1 parent 5b32a56 commit 2e7580d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
12 changes: 7 additions & 5 deletions AEURLConnection/AEURLRequestFactory.h
Expand Up @@ -49,14 +49,16 @@ typedef id (^AEURLParameterProcessor)(NSDictionary *parameters, NSMutableURLRequ
// x-www-form-urlencoded format, like a browser's POST form encoding.
+ (AEURLParameterProcessor)formURLEncodedProcessor;

// A utility function to url-encode a value.
NSString * AEURLEncodedStringFromString(NSString *string);
// Utility functions to url-encode and -decode values.
NSString *AEURLEncodedStringFromString(NSString *string);
NSString *AEStringFromURLEncodedString(NSString *formEncodedString);

// A utility function to turn a dictionary into a urlencoded string.
NSString * AEQueryStringFromParameters(NSDictionary *parameters);
// Utility function to turn a dictionary into a urlencoded string and vice-versa.
NSString *AEQueryStringFromParameters(NSDictionary *parameters);
NSDictionary *AEParametersFromQueryString(NSString *queryString);

// A utility function to base-64 encode some data.
NSString * AEBase64EncodedStringFromData(NSData *data);
NSString *AEBase64EncodedStringFromData(NSData *data);

// See AEJSONProcessor for a parameter processing block that creates JSON.

Expand Down
43 changes: 41 additions & 2 deletions AEURLConnection/AEURLRequestFactory.m
Expand Up @@ -104,13 +104,13 @@ + (AEURLParameterProcessor)formURLEncodedProcessor {
// AF in the function prefix to prevent linker conflicts). Thanks AFNetworking!
// (Used with permission.)

NSString * AEURLEncodedStringFromString(NSString *string) {
NSString *AEURLEncodedStringFromString(NSString *string) {
static NSString * const kAFLegalCharactersToBeEscaped = @"?!@#$^&%*+,:;='\"`<>()[]{}/\\|~ ";

return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, (CFStringRef)kAFLegalCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) autorelease];
}

NSString * AEQueryStringFromParameters(NSDictionary *parameters) {
NSString *AEQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutableParameterComponents = [NSMutableArray array];
for (id key in [parameters allKeys]) {
NSString *component = [NSString stringWithFormat:@"%@=%@", AEURLEncodedStringFromString([key description]), AEURLEncodedStringFromString([[parameters valueForKey:key] description])];
Expand All @@ -120,6 +120,45 @@ + (AEURLParameterProcessor)formURLEncodedProcessor {
return [mutableParameterComponents componentsJoinedByString:@"&"];
}

// AEStringFromURLEncodedString and AEParametersFromQueryString
// are loosely based on Google Web Toolkit.

NSString *AEStringFromURLEncodedString(NSString *formEncodedString) {
NSMutableString *resultString = [NSMutableString stringWithString:formEncodedString];
[resultString replaceOccurrencesOfString:@"+"
withString:@" "
options:NSLiteralSearch
range:NSMakeRange(0, [resultString length])];
return [resultString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}

NSDictionary *AEParametersFromQueryString(NSString *queryString) {
NSMutableDictionary *ret = [NSMutableDictionary dictionary];
NSArray *components = [queryString componentsSeparatedByString:@"&"];
// Use reverse order so that the first occurrence of a key replaces later ones.
[components enumerateObjectsWithOptions:NSEnumerationReverse
usingBlock:^(id component, NSUInteger idx, BOOL *stop) {
if ([component length] == 0) return;

NSRange pos = [component rangeOfString:@"="];
NSString *key;
NSString *val;
if (pos.location == NSNotFound) {
key = AEStringFromURLEncodedString(component);
val = @"";
} else {
key = AEStringFromURLEncodedString([component substringToIndex:pos.location]);
val = AEStringFromURLEncodedString([component substringFromIndex:pos.location + pos.length]);
}
// stringByUnescapingQueryString returns nil on invalid UTF8
// and NSMutableDictionary raises an exception when passed nil values.
if (!key) key = @"";
if (!val) val = @"";
[ret setObject:val forKey:key];
}];
return ret;
}

NSString * AEBase64EncodedStringFromData(NSData *data) {
NSUInteger length = [data length];
NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
Expand Down
12 changes: 12 additions & 0 deletions Example/AEURLExampleTests/AEURLExampleTests.m
Expand Up @@ -8,6 +8,7 @@

#import "AEURLExampleTests.h"
#import "AEURLConnection.h"
#import "AEURLRequestFactory.h"

// This object simulates UIViewController, which can only be released on the
// main thread. (This is the root of "The Deallocation Problem"; search the
Expand Down Expand Up @@ -62,6 +63,17 @@ - (void)testMainThreadReleaseOnlyObject {
}
}

- (void)testQueryStringEncode {
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:
@"", @"empty_value",
@"blah", @"boring_value",
@"†é߆", @"aççén†é∂", nil];
NSString *s = AEQueryStringFromParameters(d);
NSDictionary *d2 = AEParametersFromQueryString(s);

STAssertEqualObjects(d, d2, @"Query string encoding or decoding failed");
}

@end


Expand Down

0 comments on commit 2e7580d

Please sign in to comment.