| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| |
| /* CFURLComponents.c |
| Copyright (c) 2015, Apple Inc. All rights reserved. |
| Responsibility: Jim Luther/Chris Linn |
| */ |
| |
| |
| #include <CoreFoundation/CFURLComponents.h> |
| #include "CFInternal.h" |
| #include "CFURLComponents_Internal.h" |
| |
| static CFTypeID __kCFURLComponentsTypeID = _kCFRuntimeNotATypeID; |
| |
| struct __CFURLComponents { |
| CFRuntimeBase _base; |
| |
| CFLock_t _lock; |
| |
| // if inited from URL, I need to keep the URL string and the parsing info |
| CFStringRef _urlString; |
| struct _URIParseInfo _parseInfo; |
| |
| /* |
| Getters will get from either the URL or the set value, so if there's a url string, I need to know if we've attempted to get the value from the url. These flags indicate if the NSURLComponents' _xxxxComponent instance variables can be used. |
| |
| Setters will set the _xxxxComponent ivar. Components that can be percent-encoded will be percent-encoded in the _xxxxComponent ivar. For example, [NSURLComponents setPath:] will percent-encode the path argument and set _pathComponent; [NSURLComponents setPercentEncodedPath:] will simply copy the path argument and set _pathComponent. |
| |
| [NSURLComponents URL] and [NSURLComponents URLRelativeToURL:] will first set all components and mark them all valid. |
| |
| [NSURLComponents init] will set _urlString to nil, all _XXXXComponentValid flags to true, and all _XXXXComponent ivars to nil. |
| */ |
| |
| // these flags indicate if the _schemeComponent through _fragmentComponent ivars are valid or not. |
| uint32_t _schemeComponentValid : 1; |
| uint32_t _userComponentValid : 1; |
| uint32_t _passwordComponentValid : 1; |
| uint32_t _hostComponentValid : 1; |
| uint32_t _portComponentValid : 1; |
| uint32_t _pathComponentValid : 1; |
| uint32_t _queryComponentValid : 1; |
| uint32_t _fragmentComponentValid : 1; |
| |
| // These ivars are used by the getters and by [NSURLComponents URL] and [NSURLComponents URLRelativeToURL:]. The values (if not nil) are always correctly percent-encoded. |
| CFStringRef _schemeComponent; |
| CFStringRef _userComponent; |
| CFStringRef _passwordComponent; |
| CFStringRef _hostComponent; |
| CFNumberRef _portComponent; |
| CFStringRef _pathComponent; |
| CFStringRef _queryComponent; |
| CFStringRef _fragmentComponent; |
| }; |
| |
| static Boolean __CFURLComponentsEqual(CFTypeRef left, CFTypeRef right); |
| |
| static CFStringRef __CFURLComponentsCopyDescription(CFTypeRef cf) { |
| return CFSTR("A really nice CFURLComponents object"); |
| } |
| |
| CF_SWIFT_EXPORT void __CFURLComponentsDeallocate(CFURLComponentsRef instance) { |
| __CFGenericValidateType(instance, _CFURLComponentsGetTypeID()); |
| |
| if (instance->_urlString) CFRelease(instance->_urlString); |
| if (instance->_schemeComponent) CFRelease(instance->_schemeComponent); |
| if (instance->_userComponent) CFRelease(instance->_userComponent); |
| if (instance->_passwordComponent) CFRelease(instance->_passwordComponent); |
| if (instance->_hostComponent) CFRelease(instance->_hostComponent); |
| if (instance->_portComponent) CFRelease(instance->_portComponent); |
| if (instance->_pathComponent) CFRelease(instance->_pathComponent); |
| if (instance->_queryComponent) CFRelease(instance->_queryComponent); |
| if (instance->_fragmentComponent) CFRelease(instance->_fragmentComponent); |
| if (instance) CFAllocatorDeallocate(kCFAllocatorSystemDefault, instance); |
| } |
| |
| static const CFRuntimeClass __CFURLComponentsClass = { |
| 0, |
| "CFURLComponents", |
| NULL, // init |
| NULL, // copy |
| __CFURLComponentsDeallocate, |
| __CFURLComponentsEqual, |
| NULL, // hash |
| NULL, // |
| __CFURLComponentsCopyDescription |
| }; |
| |
| CFTypeID _CFURLComponentsGetTypeID(void) { |
| static dispatch_once_t initOnce; |
| dispatch_once(&initOnce, ^{ __kCFURLComponentsTypeID = _CFRuntimeRegisterClass(&__CFURLComponentsClass); }); |
| return __kCFURLComponentsTypeID; |
| } |
| |
| CF_EXPORT CFURLComponentsRef _CFURLComponentsCreate(CFAllocatorRef alloc) { |
| CFIndex size = sizeof(struct __CFURLComponents) - sizeof(CFRuntimeBase); |
| CFURLComponentsRef memory = (CFURLComponentsRef)_CFRuntimeCreateInstance(alloc, _CFURLComponentsGetTypeID(), size, NULL); |
| if (NULL == memory) { |
| return NULL; |
| } |
| |
| memory->_lock = CFLockInit; |
| |
| memory->_urlString = NULL; |
| memory->_schemeComponentValid = true; |
| memory->_userComponentValid = true; |
| memory->_passwordComponentValid = true; |
| memory->_hostComponentValid = true; |
| memory->_portComponentValid = true; |
| memory->_pathComponentValid = true; |
| memory->_queryComponentValid = true; |
| memory->_fragmentComponentValid = true; |
| |
| memory->_schemeComponent = NULL; |
| memory->_userComponent = NULL; |
| memory->_passwordComponent = NULL; |
| memory->_hostComponent = NULL; |
| memory->_portComponent = NULL; |
| memory->_pathComponent = NULL; |
| memory->_queryComponent = NULL; |
| memory->_fragmentComponent = NULL; |
| |
| return memory; |
| } |
| |
| CF_EXPORT CFURLComponentsRef _CFURLComponentsCreateWithURL(CFAllocatorRef alloc, CFURLRef url, Boolean resolveAgainstBaseURL) { |
| CFURLComponentsRef result = NULL; |
| if (resolveAgainstBaseURL) { |
| CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); |
| if (absoluteURL) { |
| result = _CFURLComponentsCreateWithString(alloc, CFURLGetString(absoluteURL)); |
| CFRelease(absoluteURL); |
| } |
| } else { |
| result = _CFURLComponentsCreateWithString(alloc, CFURLGetString(url)); |
| } |
| return result; |
| } |
| |
| CF_EXPORT CFURLComponentsRef _CFURLComponentsCreateWithString(CFAllocatorRef alloc, CFStringRef string) { |
| CFIndex size = sizeof(struct __CFURLComponents) - sizeof(CFRuntimeBase); |
| CFURLComponentsRef memory = (CFURLComponentsRef)_CFRuntimeCreateInstance(alloc, _CFURLComponentsGetTypeID(), size, NULL); |
| if (NULL == memory) { |
| return NULL; |
| } |
| |
| _CFURIParserParseURIReference(string, &memory->_parseInfo); |
| if (!_CFURIParserURLStringIsValid(string, &memory->_parseInfo)) { |
| CFAllocatorDeallocate(alloc, memory); |
| return NULL; |
| } |
| |
| memory->_lock = CFLockInit; |
| |
| memory->_urlString = CFStringCreateCopy(alloc, string); |
| memory->_schemeComponentValid = false; |
| memory->_userComponentValid = false; |
| memory->_passwordComponentValid = false; |
| memory->_hostComponentValid = false; |
| memory->_portComponentValid = false; |
| memory->_pathComponentValid = false; |
| memory->_queryComponentValid = false; |
| memory->_fragmentComponentValid = false; |
| |
| memory->_schemeComponent = NULL; |
| memory->_userComponent = NULL; |
| memory->_passwordComponent = NULL; |
| memory->_hostComponent = NULL; |
| memory->_portComponent = NULL; |
| memory->_pathComponent = NULL; |
| memory->_queryComponent = NULL; |
| memory->_fragmentComponent = NULL; |
| |
| // if paramExists, there's a semi-colon in the path |
| if (memory->_parseInfo.paramExists) { |
| CFStringRef path = _CFURLComponentsCopyPath(memory); |
| _CFURLComponentsSetPath(memory, path); |
| CFRelease(path); |
| } |
| |
| return memory; |
| } |
| |
| CF_EXPORT CFURLComponentsRef _CFURLComponentsCreateCopy(CFAllocatorRef alloc, CFURLComponentsRef components) { |
| CFIndex size = sizeof(struct __CFURLComponents) - sizeof(CFRuntimeBase); |
| CFURLComponentsRef memory = (CFURLComponentsRef)_CFRuntimeCreateInstance(alloc, _CFURLComponentsGetTypeID(), size, NULL); |
| if (NULL == memory) { |
| return NULL; |
| } |
| |
| __CFLock(&components->_lock); |
| memory->_lock = CFLockInit; |
| memory->_urlString = components->_urlString ? CFStringCreateCopy(alloc, components->_urlString) : NULL; |
| memory->_parseInfo = components->_parseInfo; |
| |
| memory->_schemeComponentValid = components->_schemeComponentValid; |
| memory->_userComponentValid = components->_userComponentValid; |
| memory->_hostComponentValid = components->_hostComponentValid; |
| memory->_passwordComponentValid = components->_passwordComponentValid; |
| memory->_portComponentValid = components->_portComponentValid; |
| memory->_pathComponentValid = components->_pathComponentValid; |
| memory->_queryComponentValid = components->_queryComponentValid; |
| memory->_fragmentComponentValid = components->_fragmentComponentValid; |
| |
| memory->_schemeComponent = components->_schemeComponent ? CFStringCreateCopy(alloc, components->_schemeComponent) : NULL; |
| memory->_userComponent = components->_userComponent ? CFStringCreateCopy(alloc, components->_userComponent) : NULL;; |
| memory->_passwordComponent = components->_passwordComponent ? CFStringCreateCopy(alloc, components->_passwordComponent) : NULL;; |
| memory->_hostComponent = components->_hostComponent ? CFStringCreateCopy(alloc, components->_hostComponent) : NULL;; |
| if (components->_portComponent) { |
| long long port = 0; |
| CFNumberGetValue(components->_portComponent, kCFNumberLongLongType, &port); |
| memory->_portComponent = CFNumberCreate(alloc, kCFNumberLongLongType, &port); |
| } else { |
| memory->_portComponent = NULL; |
| } |
| memory->_pathComponent = components->_pathComponent ? CFStringCreateCopy(alloc, components->_pathComponent) : NULL;; |
| memory->_queryComponent = components->_queryComponent ? CFStringCreateCopy(alloc, components->_queryComponent) : NULL;; |
| memory->_fragmentComponent = components->_fragmentComponent ? CFStringCreateCopy(alloc, components->_fragmentComponent) : NULL;; |
| |
| __CFUnlock(&components->_lock); |
| |
| return memory; |
| } |
| |
| #pragma mark - |
| |
| static Boolean __CFURLComponentsEqual(CFTypeRef cf1, CFTypeRef cf2) { |
| CFURLComponentsRef left = (CFURLComponentsRef)cf1; |
| CFURLComponentsRef right = (CFURLComponentsRef)cf2; |
| |
| __CFGenericValidateType(left, CFURLGetTypeID()); |
| __CFGenericValidateType(right, CFURLGetTypeID()); |
| |
| if (left == right) { |
| return true; |
| } |
| |
| Boolean (^componentEqual)(CFTypeRef l, CFTypeRef r) = ^(CFTypeRef l, CFTypeRef r) { |
| // if pointers are equal (including both nil), they are equal; otherwise, use isEqual |
| if (l == r) { |
| return (Boolean)true; |
| } else { |
| return CFEqual(left, r); |
| } |
| }; |
| |
| CFStringRef leftPath = _CFURLComponentsCopyPercentEncodedPath(left); |
| CFStringRef rightPath = _CFURLComponentsCopyPercentEncodedPath(right); |
| |
| CFStringRef leftHost = _CFURLComponentsCopyPercentEncodedHost(left); |
| CFStringRef rightHost = _CFURLComponentsCopyPercentEncodedHost(right); |
| |
| CFStringRef leftQuery = _CFURLComponentsCopyPercentEncodedQuery(left); |
| CFStringRef rightQuery = _CFURLComponentsCopyPercentEncodedQuery(right); |
| |
| CFStringRef leftFragment = _CFURLComponentsCopyPercentEncodedFragment(left); |
| CFStringRef rightFragment = _CFURLComponentsCopyPercentEncodedFragment(right); |
| |
| CFStringRef leftUser = _CFURLComponentsCopyPercentEncodedUser(left); |
| CFStringRef rightUser = _CFURLComponentsCopyPercentEncodedUser(right); |
| |
| CFStringRef leftPassword = _CFURLComponentsCopyPercentEncodedPassword(left); |
| CFStringRef rightPassword = _CFURLComponentsCopyPercentEncodedPassword(right); |
| |
| |
| Boolean result = |
| componentEqual(left->_schemeComponent, right->_schemeComponent) && |
| componentEqual(leftPath, rightPath) && |
| componentEqual(leftHost, rightHost) && |
| componentEqual(left->_portComponent, right->_portComponent) && |
| componentEqual(leftQuery, rightQuery) && |
| componentEqual(leftFragment, rightFragment) && |
| componentEqual(leftUser, rightUser) && |
| componentEqual(leftPassword, rightPassword); |
| |
| if (leftPath) CFRelease(leftPath); |
| if (rightPath) CFRelease(rightPath); |
| |
| if (leftHost) CFRelease(leftHost); |
| if (rightHost) CFRelease(rightHost); |
| |
| if (leftQuery) CFRelease(leftQuery); |
| if (rightQuery) CFRelease(rightQuery); |
| |
| if (leftFragment) CFRelease(leftFragment); |
| if (rightFragment) CFRelease(rightFragment); |
| |
| if (leftUser) CFRelease(leftUser); |
| if (rightUser) CFRelease(rightUser); |
| |
| if (leftPassword) CFRelease(leftPassword); |
| if (rightPassword) CFRelease(rightPassword); |
| |
| return result; |
| } |
| |
| CF_EXPORT CFURLRef _CFURLComponentsCopyURL(CFURLComponentsRef components) { |
| return _CFURLComponentsCopyURLRelativeToURL(components, NULL); |
| } |
| |
| CF_EXPORT CFURLRef _CFURLComponentsCopyURLRelativeToURL(CFURLComponentsRef components, CFURLRef relativeToURL) { |
| CFStringRef urlString = _CFURLComponentsCopyString(components); |
| if (urlString) { |
| CFURLRef url = CFURLCreateWithString(kCFAllocatorSystemDefault, urlString, relativeToURL); |
| CFRelease(urlString); |
| return url; |
| } else { |
| return NULL; |
| } |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyString(CFURLComponentsRef components) { |
| CFStringRef result = NULL; |
| |
| // make sure all of the _XXXXComponent ivars are initialized |
| if ( !components->_schemeComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyScheme(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_userComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyPercentEncodedUser(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_passwordComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyPercentEncodedPassword(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_hostComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyPercentEncodedHost(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_portComponentValid ) { |
| CFNumberRef temp = _CFURLComponentsCopyPort(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_pathComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyPercentEncodedPath(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_queryComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyPercentEncodedQuery(components); |
| if (temp) CFRelease(temp); |
| } |
| if ( !components->_fragmentComponentValid ) { |
| CFStringRef temp = _CFURLComponentsCopyPercentEncodedFragment(components); |
| if (temp) CFRelease(temp); |
| } |
| |
| Boolean hasAuthority = (components->_userComponent || components->_passwordComponent || components->_hostComponent || components->_portComponent); |
| // If there's an authority component and a path component, then the path must either begin with "/" or be an empty string. |
| if ( hasAuthority && components->_pathComponent && CFStringGetLength(components->_pathComponent) && (CFStringGetCharacterAtIndex(components->_pathComponent, 0) != '/') ) { |
| result = NULL; |
| } |
| // If there's no authority component and a path component, the path component must not start with "//". |
| else if ( !hasAuthority && components->_pathComponent && CFStringGetLength(components->_pathComponent) >= 2 && (CFStringGetCharacterAtIndex(components->_pathComponent, 0) == '/') && (CFStringGetCharacterAtIndex(components->_pathComponent, 1) == '/') ) { |
| result = NULL; |
| } |
| else { |
| __CFLock(&components->_lock); |
| |
| CFStringAppendBuffer buf; |
| UniChar chars[2]; |
| |
| // create the URL string |
| CFStringInitAppendBuffer(kCFAllocatorDefault, &buf); |
| |
| if ( components->_schemeComponent ) { |
| // append "<scheme>:" |
| CFStringAppendStringToAppendBuffer(&buf, components->_schemeComponent); |
| chars[0] = ':'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| } |
| if ( components->_userComponent || components->_passwordComponent || components->_hostComponent || components->_portComponent ) { |
| // append "//" |
| chars[0] = chars[1] = '/'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 2); |
| } |
| if ( components->_userComponent ) { |
| // append "<user>" |
| CFStringAppendStringToAppendBuffer(&buf, components->_userComponent); |
| } |
| if ( components->_passwordComponent ) { |
| // append ":<password>" |
| chars[0] = ':'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| CFStringAppendStringToAppendBuffer(&buf, components->_passwordComponent); |
| } |
| if ( components->_userComponent || components->_passwordComponent ) { |
| // append "@" |
| chars[0] = '@'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| } |
| if ( components->_hostComponent ) { |
| // append "<host>" |
| CFStringAppendStringToAppendBuffer(&buf, components->_hostComponent); |
| } |
| if ( components->_portComponent ) { |
| // append ":<port>" |
| chars[0] = ':'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| #define LONG_LONG_MAX_DIGITS 19 |
| long long num; |
| if (!CFNumberGetValue(components->_portComponent, kCFNumberLongLongType, &num)) { |
| num = 0; |
| } |
| char numStr[LONG_LONG_MAX_DIGITS + 1] = {0}; |
| snprintf(numStr, LONG_LONG_MAX_DIGITS, "%lld", num); |
| CFStringRef portStr = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)numStr, strlen(numStr), kCFStringEncodingASCII, false); |
| CFStringAppendStringToAppendBuffer(&buf, (CFStringRef)portStr); |
| CFRelease(portStr); |
| #undef LONG_LONG_MAX_DIGITS |
| } |
| if ( components->_pathComponent ) { |
| // append "<path>" |
| CFStringAppendStringToAppendBuffer(&buf, components->_pathComponent); |
| } |
| if ( components->_queryComponent ) { |
| // append "?<query>" |
| chars[0] = '?'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| CFStringAppendStringToAppendBuffer(&buf, components->_queryComponent); |
| } |
| if ( components->_fragmentComponent ) { |
| // append "#<fragment>" |
| chars[0] = '#'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| CFStringAppendStringToAppendBuffer(&buf, components->_fragmentComponent); |
| } |
| result = CFStringCreateMutableWithAppendBuffer(&buf); |
| __CFUnlock(&components->_lock); |
| } |
| |
| return ( result ); |
| } |
| |
| static inline CFStringRef CreateComponentWithURLStringRange(CFStringRef urlString, CFRange range) |
| { |
| // the component has never been set so no nee to release it |
| if ( range.location != kCFNotFound ) { |
| CFRange theRange; |
| theRange.location = range.location; |
| theRange.length = range.length; |
| return CFStringCreateWithSubstring(kCFAllocatorSystemDefault, urlString, theRange); |
| } |
| else { |
| return NULL; |
| } |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyScheme(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_schemeComponentValid ) { |
| components->_schemeComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetSchemeRange(&components->_parseInfo, false)); |
| components->_schemeComponentValid = true; |
| } |
| result = components->_schemeComponent ? CFRetain(components->_schemeComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyUser(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_userComponentValid ) { |
| components->_userComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetUserinfoNameRange(&components->_parseInfo, false)); |
| components->_userComponentValid = true; |
| } |
| result = components->_userComponent ? _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, components->_userComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPassword(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_passwordComponentValid ) { |
| components->_passwordComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetUserinfoPasswordRange(&components->_parseInfo, false)); |
| components->_passwordComponentValid = true; |
| } |
| result = components->_passwordComponent ? _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, components->_passwordComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyHost(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_hostComponentValid ) { |
| components->_hostComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetHostRange(&components->_parseInfo, false)); |
| components->_hostComponentValid = true; |
| } |
| result = components->_hostComponent ? _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, components->_hostComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFNumberRef _CFURLComponentsCopyPort(CFURLComponentsRef components) { |
| CFNumberRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_portComponentValid ) { |
| CFRange range = _CFURIParserGetPortRange(&components->_parseInfo, false); |
| // rfc3986 says URI producers should omit the port component and its ":" delimiter if port is empty. |
| if ( range.location != kCFNotFound && range.length != 0) { |
| CFStringRef portString = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, components->_urlString, CFRangeMake(range.location, range.length)); |
| char buf[16]; |
| if (!CFStringGetCString(portString, buf, 16, kCFStringEncodingASCII)) { |
| HALT; |
| } |
| long long value; |
| #if DEPLOYMENT_TARGET_LINUX |
| if (sscanf(buf, "%lld", &value) != 1) { |
| HALT; |
| } |
| #else |
| if (sscanf_l(buf, NULL, "%lld", &value) != 1) { |
| HALT; |
| } |
| #endif |
| components->_portComponent = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberLongLongType, &value); |
| CFRelease(portString); |
| } |
| else { |
| components->_portComponent = nil; |
| } |
| components->_portComponentValid = true; |
| } |
| result = components->_portComponent ? CFRetain(components->_portComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPath(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_pathComponentValid ) { |
| components->_pathComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetPathRange(&components->_parseInfo, false, false)); |
| components->_pathComponentValid = true; |
| } |
| if (!components->_pathComponent) { |
| result = CFSTR(""); |
| } else { |
| result = _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, components->_pathComponent); |
| if (!result) { |
| result = CFSTR(""); |
| } |
| } |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyQuery(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_queryComponentValid ) { |
| components->_queryComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetQueryRange(&components->_parseInfo, false)); |
| components->_queryComponentValid = true; |
| } |
| result = components->_queryComponent ? _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, components->_queryComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyFragment(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_fragmentComponentValid ) { |
| components->_fragmentComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetFragmentRange(&components->_parseInfo, false)); |
| components->_fragmentComponentValid = true; |
| } |
| result = components->_fragmentComponent ? _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, components->_fragmentComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetScheme(CFURLComponentsRef components, CFStringRef scheme) { |
| if ( scheme ) { |
| Boolean valid = false; |
| CFIndex length = CFStringGetLength(scheme); |
| if ( length != 0 ) { |
| UniChar ch = CFStringGetCharacterAtIndex(scheme, 0); |
| valid = (ch <= 127) && _CFURIParserAlphaAllowed(ch) && _CFURIParserValidateComponent(scheme, CFRangeMake(1, length - 1), kURLSchemeAllowed, false); |
| } |
| if ( !valid ) { |
| // invalid characters in scheme |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_schemeComponent) CFRelease(components->_schemeComponent); |
| components->_schemeComponent = scheme ? CFStringCreateCopy(kCFAllocatorSystemDefault, scheme) : NULL; |
| components->_schemeComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetUser(CFURLComponentsRef components, CFStringRef user) { |
| __CFLock(&components->_lock); |
| if (components->_userComponent) CFRelease(components->_userComponent); |
| components->_userComponent = user ? _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, user, _CFURLComponentsGetURLUserAllowedCharacterSet()) : NULL; |
| components->_userComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPassword(CFURLComponentsRef components, CFStringRef password) { |
| __CFLock(&components->_lock); |
| if (components->_passwordComponent) CFRelease(components->_passwordComponent); |
| components->_passwordComponent = password ? _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, password, _CFURLComponentsGetURLPasswordAllowedCharacterSet()) : NULL; |
| components->_passwordComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetHost(CFURLComponentsRef components, CFStringRef host) { |
| __CFLock(&components->_lock); |
| if (components->_hostComponent) CFRelease(components->_hostComponent); |
| components->_hostComponent = host ? _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, host, _CFURLComponentsGetURLHostAllowedCharacterSet()) : NULL; |
| components->_hostComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPort(CFURLComponentsRef components, CFNumberRef port) { |
| long long portNumber = 0; |
| if ( port ) { |
| // make sure the port number is a non-negative integer |
| if ( !CFNumberGetValue(port, kCFNumberLongLongType, &portNumber) || portNumber < 0 ) { |
| // negative port number |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_portComponent) CFRelease(components->_portComponent); |
| if (port) { |
| components->_portComponent = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberLongLongType, &portNumber); |
| } else { |
| components->_portComponent = NULL; |
| } |
| components->_portComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPath(CFURLComponentsRef components, CFStringRef path) { |
| __CFLock(&components->_lock); |
| if (components->_pathComponent) CFRelease(components->_pathComponent); |
| components->_pathComponent = path ? _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, path, _CFURLComponentsGetURLPathAllowedCharacterSet()) : NULL; |
| components->_pathComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetQuery(CFURLComponentsRef components, CFStringRef query) { |
| __CFLock(&components->_lock); |
| if (components->_queryComponent) CFRelease(components->_queryComponent); |
| components->_queryComponent = query ? _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, query, _CFURLComponentsGetURLQueryAllowedCharacterSet()) : NULL; |
| components->_queryComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetFragment(CFURLComponentsRef components, CFStringRef fragment) { |
| __CFLock(&components->_lock); |
| if (components->_fragmentComponent) CFRelease(components->_fragmentComponent); |
| components->_fragmentComponent = fragment ? _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, fragment, _CFURLComponentsGetURLFragmentAllowedCharacterSet()) : NULL; |
| components->_fragmentComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPercentEncodedUser(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_userComponentValid ) { |
| components->_userComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetUserinfoNameRange(&components->_parseInfo, false)); |
| components->_userComponentValid = true; |
| } |
| result = components->_userComponent ? CFRetain(components->_userComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPercentEncodedPassword(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_passwordComponentValid ) { |
| components->_passwordComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetUserinfoPasswordRange(&components->_parseInfo, false)); |
| components->_passwordComponentValid = true; |
| } |
| result = components->_passwordComponent ? CFRetain(components->_passwordComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPercentEncodedHost(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_hostComponentValid ) { |
| components->_hostComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetHostRange(&components->_parseInfo, false)); |
| components->_hostComponentValid = true; |
| } |
| result = components->_hostComponent ? CFRetain(components->_hostComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPercentEncodedPath(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_pathComponentValid ) { |
| components->_pathComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetPathRange(&components->_parseInfo, false, false)); |
| components->_pathComponentValid = true; |
| } |
| result = components->_pathComponent ? CFRetain(components->_pathComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| if (!result) result = CFSTR(""); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPercentEncodedQuery(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_queryComponentValid ) { |
| components->_queryComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetQueryRange(&components->_parseInfo, false)); |
| components->_queryComponentValid = true; |
| } |
| result = components->_queryComponent ? CFRetain(components->_queryComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT CFStringRef _CFURLComponentsCopyPercentEncodedFragment(CFURLComponentsRef components) { |
| CFStringRef result; |
| |
| __CFLock(&components->_lock); |
| if ( !components->_fragmentComponentValid ) { |
| components->_fragmentComponent = CreateComponentWithURLStringRange(components->_urlString, _CFURIParserGetFragmentRange(&components->_parseInfo, false)); |
| components->_fragmentComponentValid = true; |
| } |
| result = components->_fragmentComponent ? CFRetain(components->_fragmentComponent) : NULL; |
| __CFUnlock(&components->_lock); |
| |
| return ( result ); |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPercentEncodedUser(CFURLComponentsRef components, CFStringRef percentEncodedUser) { |
| if ( percentEncodedUser ) { |
| if ( !_CFURIParserValidateComponent(percentEncodedUser, CFRangeMake(0, CFStringGetLength(percentEncodedUser)), kURLUserAllowed, true) ) { |
| // invalid characters in percentEncodedUser |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_userComponent) CFRelease(components->_userComponent); |
| components->_userComponent = percentEncodedUser ? CFStringCreateCopy(kCFAllocatorSystemDefault, percentEncodedUser) : NULL; |
| components->_userComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPercentEncodedPassword(CFURLComponentsRef components, CFStringRef percentEncodedPassword) { |
| if ( percentEncodedPassword ) { |
| if ( !_CFURIParserValidateComponent(percentEncodedPassword, CFRangeMake(0, CFStringGetLength(percentEncodedPassword)), kURLPasswordAllowed, true) ) { |
| // invalid characters in percentEncodedPassword |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_passwordComponent) CFRelease(components->_passwordComponent); |
| components->_passwordComponent = percentEncodedPassword ? CFStringCreateCopy(kCFAllocatorSystemDefault, percentEncodedPassword) : NULL; |
| components->_passwordComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPercentEncodedHost(CFURLComponentsRef components, CFStringRef percentEncodedHost) { |
| if ( percentEncodedHost ) { |
| CFIndex length = CFStringGetLength(percentEncodedHost); |
| CFRange componentRange; |
| if ( (length >= 2) && (CFStringGetCharacterAtIndex(percentEncodedHost, 0) == '[') && (CFStringGetCharacterAtIndex(percentEncodedHost, length - 1) == ']') ) { |
| // the host is an IP-Literal -- only validate the characters inside brackets |
| componentRange = CFRangeMake(1, length - 2); |
| } |
| else { |
| componentRange = CFRangeMake(0, length); |
| } |
| if ( !_CFURIParserValidateComponent(percentEncodedHost, componentRange, kURLHostAllowed, true) ) { |
| // invalid characters in percentEncodedHost |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_hostComponent) CFRelease(components->_hostComponent); |
| components->_hostComponent = percentEncodedHost ? CFStringCreateCopy(kCFAllocatorSystemDefault, percentEncodedHost) : NULL; |
| components->_hostComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPercentEncodedPath(CFURLComponentsRef components, CFStringRef percentEncodedPath) { |
| if ( percentEncodedPath ) { |
| if ( !_CFURIParserValidateComponent(percentEncodedPath, CFRangeMake(0, CFStringGetLength(percentEncodedPath)), kURLPathAllowed, true) ) { |
| // invalid characters in percentEncodedPath |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_pathComponent) CFRelease(components->_pathComponent); |
| components->_pathComponent = percentEncodedPath ? CFStringCreateCopy(kCFAllocatorSystemDefault, percentEncodedPath) : NULL; |
| components->_pathComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPercentEncodedQuery(CFURLComponentsRef components, CFStringRef percentEncodedQuery) { |
| if ( percentEncodedQuery ) { |
| if ( !_CFURIParserValidateComponent(percentEncodedQuery, CFRangeMake(0, CFStringGetLength(percentEncodedQuery)), kURLQueryAllowed, true) ) { |
| // invalid characters in percentEncodedQuery |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_queryComponent) CFRelease(components->_queryComponent); |
| components->_queryComponent = percentEncodedQuery ? CFStringCreateCopy(kCFAllocatorSystemDefault, percentEncodedQuery) : NULL; |
| components->_queryComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| CF_EXPORT Boolean _CFURLComponentsSetPercentEncodedFragment(CFURLComponentsRef components, CFStringRef percentEncodedFragment) { |
| if ( percentEncodedFragment ) { |
| if ( !_CFURIParserValidateComponent(percentEncodedFragment, CFRangeMake(0, CFStringGetLength(percentEncodedFragment)), kURLFragmentAllowed, true) ) { |
| // invalid characters in percentEncodedFragment |
| return false; |
| } |
| } |
| __CFLock(&components->_lock); |
| if (components->_fragmentComponent) CFRelease(components->_fragmentComponent); |
| components->_fragmentComponent = percentEncodedFragment ? CFStringCreateCopy(kCFAllocatorSystemDefault, percentEncodedFragment) : NULL; |
| components->_fragmentComponentValid = true; |
| __CFUnlock(&components->_lock); |
| return true; |
| } |
| |
| static Boolean _CFURLComponentsParseInfoIsValid(CFURLComponentsRef components) { |
| // if all _xxxxComponentValid flags are false, then _urlString is the string and _parseInfo is valid |
| return ( !components->_schemeComponentValid && !components->_userComponentValid && !components->_passwordComponentValid && !components->_hostComponentValid && !components->_portComponentValid && !components->_pathComponentValid && !components->_queryComponentValid && !components->_fragmentComponentValid); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfScheme(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetSchemeRange(theParseInfo, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfUser(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetUserinfoNameRange(theParseInfo, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfPassword(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetUserinfoPasswordRange(theParseInfo, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfHost(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetHostRange(theParseInfo, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfPort(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetPortRange(theParseInfo, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfPath(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetPathRange(theParseInfo, false, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfQuery(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetQueryRange(theParseInfo, false) ); |
| } |
| |
| CF_EXPORT CFRange _CFURLComponentsGetRangeOfFragment(CFURLComponentsRef components) { |
| struct _URIParseInfo stringParseInfo; |
| struct _URIParseInfo *theParseInfo; |
| if ( _CFURLComponentsParseInfoIsValid(components) ) { |
| // use the range info in _URIParseInfo is valid |
| theParseInfo = &components->_parseInfo; |
| } |
| else { |
| // we need to get the current string, parse it, and use its range info |
| theParseInfo = &stringParseInfo; |
| CFStringRef str = _CFURLComponentsCopyString(components); |
| _CFURIParserParseURIReference(str, theParseInfo); |
| CFRelease(str); |
| } |
| return ( _CFURIParserGetFragmentRange(theParseInfo, false) ); |
| } |
| |
| // Returns an array of dictionaries; each dictionary has two keys: "name", for the name, and "value" for the value. If one of the keys is missing then we did not populate that part of the entry. |
| CF_EXPORT CFArrayRef _CFURLComponentsCopyQueryItems(CFURLComponentsRef components) { |
| CFStringRef queryString = _CFURLComponentsCopyPercentEncodedQuery(components); |
| CFArrayRef result = NULL; |
| |
| if ( queryString ) { |
| CFIndex len = CFStringGetLength(queryString); |
| if ( len ) { |
| CFMutableArrayRef intermediateResult = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); |
| |
| CFStringInlineBuffer buf; |
| CFStringInitInlineBuffer((CFStringRef)queryString, &buf, CFRangeMake(0, len)); |
| CFStringRef nameString; |
| CFStringRef valueString; |
| CFRange nameRange; |
| CFRange valueRange; |
| nameRange.location = 0; |
| valueRange.location = kCFNotFound; |
| CFIndex idx = 0; |
| Boolean sawPercent = false; |
| for ( idx = 0; idx < len; ++idx ) { |
| UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, idx); |
| if ( ch == '=' ) { |
| if ( nameRange.location != kCFNotFound ) { |
| // found the end of the name string |
| nameRange.length = idx - nameRange.location; |
| if ( nameRange.length ) { |
| nameString = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, queryString, nameRange); |
| if ( sawPercent ) { |
| CFStringRef temp = _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, nameString); |
| CFRelease(nameString); |
| nameString = temp; |
| sawPercent = false; |
| } |
| } |
| else { |
| nameString = CFSTR(""); |
| } |
| nameRange.location = kCFNotFound; |
| valueRange.location = idx + 1; |
| } |
| // else found an '=' that is part of the value string |
| } |
| else if ( ch == '&' ) { |
| // found end of name-value pair |
| if ( valueRange.location != kCFNotFound ) { |
| // found the end of the value string |
| valueRange.length = idx - valueRange.location; |
| if ( valueRange.length ) { |
| valueString = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, queryString, valueRange); |
| if ( sawPercent ) { |
| CFStringRef temp = _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, valueString); |
| CFRelease(valueString); |
| valueString = temp; |
| sawPercent = false; |
| } |
| } |
| else { |
| valueString = CFSTR(""); |
| } |
| CFStringRef name = CFSTR("name"); |
| CFTypeRef keys[] = {name, CFSTR("value")}; |
| CFTypeRef values[] = {nameString, valueString}; |
| CFDictionaryRef entry = CFDictionaryCreate(kCFAllocatorSystemDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
| CFArrayAppendValue(intermediateResult, entry); |
| CFRelease(entry); |
| valueRange.location = kCFNotFound; |
| CFRelease(nameString); |
| CFRelease(valueString); |
| } |
| else { |
| // there was no value string, so this was the end of the name string |
| nameRange.length = idx - nameRange.location; |
| if ( nameRange.length ) { |
| nameString = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, queryString, nameRange); |
| if ( sawPercent ) { |
| CFStringRef temp = _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, nameString); |
| CFRelease(nameString); |
| nameString = temp; |
| sawPercent = false; |
| } |
| } |
| else { |
| nameString = CFSTR(""); |
| } |
| CFStringRef name = CFSTR("name"); |
| CFTypeRef keys[] = {name}; |
| CFTypeRef values[] = {nameString}; |
| CFDictionaryRef entry = CFDictionaryCreate(kCFAllocatorSystemDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
| CFArrayAppendValue(intermediateResult, entry); |
| CFRelease(entry); |
| CFRelease(nameString); |
| } |
| nameRange.location = idx + 1; |
| } |
| else if ( ch == '%' ) { |
| sawPercent = YES; |
| } |
| } |
| |
| if ( valueRange.location != kCFNotFound ) { |
| // at end of query while parsing the value string |
| valueRange.length = idx - valueRange.location; |
| if ( valueRange.length ) { |
| valueString = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, queryString, valueRange); |
| if ( sawPercent ) { |
| CFStringRef temp = _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, valueString); |
| CFRelease(valueString); |
| valueString = temp; |
| sawPercent = false; |
| } |
| } |
| else { |
| valueString = CFSTR(""); |
| } |
| CFStringRef name = CFSTR("name"); |
| CFTypeRef keys[] = {name, CFSTR("value")}; |
| CFTypeRef values[] = {nameString, valueString}; |
| CFDictionaryRef entry = CFDictionaryCreate(kCFAllocatorSystemDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
| CFArrayAppendValue(intermediateResult, entry); |
| CFRelease(entry); |
| CFRelease(nameString); |
| CFRelease(valueString); |
| } |
| else { |
| // at end of query while parsing the name string |
| nameRange.length = idx - nameRange.location; |
| if ( nameRange.length ) { |
| nameString = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, queryString, nameRange); |
| if ( sawPercent ) { |
| CFStringRef temp = _CFStringCreateByRemovingPercentEncoding(kCFAllocatorSystemDefault, nameString); |
| CFRelease(nameString); |
| nameString = temp; |
| sawPercent = false; |
| } |
| } |
| else { |
| nameString = CFSTR(""); |
| } |
| CFStringRef name = CFSTR("name"); |
| CFTypeRef keys[] = {name}; |
| CFTypeRef values[] = {nameString}; |
| CFDictionaryRef entry = CFDictionaryCreate(kCFAllocatorSystemDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
| CFArrayAppendValue(intermediateResult, entry); |
| CFRelease(entry); |
| CFRelease(nameString); |
| } |
| |
| result = (CFArrayRef)intermediateResult; |
| } |
| else { |
| // If the query component is an empty string, return an empty array |
| result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); |
| } |
| |
| CFRelease(queryString); |
| } |
| else { |
| // If there is no query component, return nothing |
| } |
| return ( result ); |
| } |
| |
| // n.b. names and values must have the same length |
| CF_EXPORT void _CFURLComponentsSetQueryItems(CFURLComponentsRef components, CFArrayRef names, CFArrayRef values) { |
| if ( names != NULL ) { |
| if ( CFArrayGetCount(names) != CFArrayGetCount(values) ) HALT; |
| if ( CFArrayGetCount(names) ) { |
| CFStringAppendBuffer buf; |
| CFStringInitAppendBuffer(kCFAllocatorDefault, &buf); |
| UniChar chars[1]; |
| static CFMutableCharacterSetRef queryNameValueAllowed = NULL; |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| queryNameValueAllowed = CFCharacterSetCreateMutableCopy(kCFAllocatorSystemDefault, _CFURLComponentsGetURLQueryAllowedCharacterSet()); |
| CFCharacterSetRemoveCharactersInString(queryNameValueAllowed, CFSTR("&=")); |
| }); |
| CFIndex namesLength = CFArrayGetCount(names); |
| Boolean first = true; |
| for (CFIndex i = 0; i < namesLength; i++) { |
| if ( !first ) { |
| chars[0] = '&'; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| } |
| else { |
| first = false; |
| } |
| CFTypeRef name = CFArrayGetValueAtIndex(names, i); |
| CFTypeRef value = CFArrayGetValueAtIndex(values, i); |
| if ( name && name != kCFNull ) { |
| CFStringRef stringWithPercentEncoding = _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, name, queryNameValueAllowed); |
| CFStringAppendStringToAppendBuffer(&buf, stringWithPercentEncoding); |
| CFRelease(stringWithPercentEncoding); |
| } |
| if ( value && value != kCFNull ) { |
| chars[0] = '='; |
| CFStringAppendCharactersToAppendBuffer(&buf, chars, 1); |
| CFStringRef stringWithPercentEncoding = _CFStringCreateByAddingPercentEncodingWithAllowedCharacters(kCFAllocatorSystemDefault, value, queryNameValueAllowed); |
| CFStringAppendStringToAppendBuffer(&buf, stringWithPercentEncoding); |
| CFRelease(stringWithPercentEncoding); |
| } |
| // else the query item string will be simply "name" |
| } |
| CFStringRef queryString = CFStringCreateMutableWithAppendBuffer(&buf); |
| _CFURLComponentsSetPercentEncodedQuery(components, queryString); |
| CFRelease(queryString); |
| } |
| else { |
| // If there's an array but the count is zero, set the query to a zero length string |
| _CFURLComponentsSetPercentEncodedQuery(components, CFSTR("")); |
| } |
| } |
| else { |
| // If there is no items array, set the query to nil |
| _CFURLComponentsSetPercentEncodedQuery(components, NULL); |
| } |
| } |