18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
2231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Copyright (C) 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1.  Redistributions of source code must retain the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer.
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2.  Redistributions in binary form must reproduce the above copyright
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer in the
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     documentation and/or other materials provided with the distribution.
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     its contributors may be used to endorse or promote products derived
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     from this software without specific prior written permission.
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebNSURLExtras.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebKitNSStringExtras.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebLocalizableStrings.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebNSDataExtras.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebNSObjectExtras.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebSystemInterface.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <Foundation/NSURLRequest.h>
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <WebCore/KURL.h>
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <WebCore/LoaderNSURLExtras.h>
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <WebKitSystemInterface.h>
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <wtf/Assertions.h>
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <unicode/uchar.h>
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <unicode/uidna.h>
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <unicode/uscript.h>
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WebCore;
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WTF;
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef void (* StringRangeApplierFunction)(NSString *string, NSRange range, void *context);
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Needs to be big enough to hold an IDN-encoded name.
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define HOST_NAME_BUFFER_LENGTH 2048
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define URL_BYTES_BUFFER_LENGTH 2048
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic pthread_once_t IDNScriptWhiteListFileRead = PTHREAD_ONCE_INIT;
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic uint32_t IDNScriptWhiteList[(USCRIPT_CODE_LIMIT + 31) / 32];
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline BOOL isLookalikeCharacter(int charCode)
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: Move this code down into WebCore so it can be shared with other platforms.
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// This function treats the following as unsafe, lookalike characters:
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// any non-printable character, any character considered as whitespace that isn't already converted to a space by ICU,
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// and any ignorable character.
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// We also considered the characters in Mozilla's blacklist (http://kb.mozillazine.org/Network.IDN.blacklist_chars),
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// and included all of these characters that ICU can encode.
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!u_isprint(charCode) || u_isUWhiteSpace(charCode) || u_hasBinaryProperty(charCode, UCHAR_DEFAULT_IGNORABLE_CODE_POINT))
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return YES;
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (charCode) {
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x00ED: /* LATIN SMALL LETTER I WITH ACUTE */
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x01C3: /* LATIN LETTER RETROFLEX CLICK */
770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x0251: /* LATIN SMALL LETTER ALPHA */
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x0261: /* LATIN SMALL LETTER SCRIPT G */
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x0337: /* COMBINING SHORT SOLIDUS OVERLAY */
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x0338: /* COMBINING LONG SOLIDUS OVERLAY */
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x05B4: /* HEBREW POINT HIRIQ */
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x05BC: /* HEBREW POINT DAGESH OR MAPIQ */
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x05C3: /* HEBREW PUNCTUATION SOF PASUQ */
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x05F4: /* HEBREW PUNCTUATION GERSHAYIM */
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x0660: /* ARABIC INDIC DIGIT ZERO */
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x06D4: /* ARABIC FULL STOP */
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x06F0: /* EXTENDED ARABIC INDIC DIGIT ZERO */
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2027: /* HYPHENATION POINT */
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2039: /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x203A: /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2044: /* FRACTION SLASH */
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2215: /* DIVISION SLASH */
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x2216: /* SET MINUS */
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x233F: /* APL FUNCTIONAL SYMBOL SLASH BAR */
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x23AE: /* INTEGRAL EXTENSION */
960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x244A: /* OCR DOUBLE BACKSLASH */
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2571: /* BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT */
980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x2572: /* BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT */
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x29F8: /* BIG SOLIDUS */
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x29f6: /* SOLIDUS WITH OVERBAR */
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2AFB: /* TRIPLE SOLIDUS BINARY RELATION */
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x2AFD: /* DOUBLE SOLIDUS OPERATOR */
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x3008: /* LEFT ANGLE BRACKET */
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x3014: /* LEFT TORTOISE SHELL BRACKET */
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x3015: /* RIGHT TORTOISE SHELL BRACKET */
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x3033: /* VERTICAL KANA REPEAT MARK UPPER HALF */
1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        case 0x3035: /* VERTICAL KANA REPEAT MARK LOWER HALF */
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x321D: /* PARENTHESIZED KOREAN CHARACTER OJEON */
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x321E: /* PARENTHESIZED KOREAN CHARACTER O HU */
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0x33DF: /* SQUARE A OVER M */
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0xFE14: /* PRESENTATION FORM FOR VERTICAL SEMICOLON */
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0xFE15: /* PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK */
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0xFE3F: /* PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET */
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0xFE5D: /* SMALL LEFT TORTOISE SHELL BRACKET */
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case 0xFE5E: /* SMALL RIGHT TORTOISE SHELL BRACKET */
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return YES;
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        default:
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic char hexDigit(int i)
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (i < 0 || i > 16) {
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("illegal hex digit");
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return '0';
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int h = i;
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (h >= 10) {
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        h = h - 10 + 'A';
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        h += '0';
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return h;
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic BOOL isHexDigit(char c)
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int hexDigitValue(char c)
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c >= '0' && c <= '9') {
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return c - '0';
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c >= 'A' && c <= 'F') {
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return c - 'A' + 10;
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c >= 'a' && c <= 'f') {
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return c - 'a' + 10;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    LOG_ERROR("illegal hex digit");
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void applyHostNameFunctionToMailToURLString(NSString *string, StringRangeApplierFunction f, void *context)
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // In a mailto: URL, host names come after a '@' character and end with a '>' or ',' or '?' character.
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Skip quoted strings so that characters in them don't confuse us.
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // When we find a '?' character, we are past the part of the URL that contains host names.
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *hostNameOrStringStartCharacters;
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hostNameOrStringStartCharacters == nil) {
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostNameOrStringStartCharacters = [NSCharacterSet characterSetWithCharactersInString:@"\"@?"];
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFRetain(hostNameOrStringStartCharacters);
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *hostNameEndCharacters;
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hostNameEndCharacters == nil) {
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostNameEndCharacters = [NSCharacterSet characterSetWithCharactersInString:@">,?"];
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFRetain(hostNameEndCharacters);
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *quotedStringCharacters;
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (quotedStringCharacters == nil) {
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        quotedStringCharacters = [NSCharacterSet characterSetWithCharactersInString:@"\"\\"];
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFRetain(quotedStringCharacters);
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned stringLength = [string length];
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSRange remaining = NSMakeRange(0, stringLength);
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find start of host name or of quoted string.
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange hostNameOrStringStart = [string rangeOfCharacterFromSet:hostNameOrStringStartCharacters options:0 range:remaining];
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hostNameOrStringStart.location == NSNotFound) {
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unichar c = [string characterAtIndex:hostNameOrStringStart.location];
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        remaining.location = NSMaxRange(hostNameOrStringStart);
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        remaining.length = stringLength - remaining.location;
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '?') {
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '@') {
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Find end of host name.
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            unsigned hostNameStart = remaining.location;
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            NSRange hostNameEnd = [string rangeOfCharacterFromSet:hostNameEndCharacters options:0 range:remaining];
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            BOOL done;
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (hostNameEnd.location == NSNotFound) {
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostNameEnd.location = stringLength;
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                done = YES;
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                remaining.location = hostNameEnd.location;
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                remaining.length = stringLength - remaining.location;
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                done = NO;
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Process host name range.
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            f(string, NSMakeRange(hostNameStart, hostNameEnd.location - hostNameStart), context);
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (done) {
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Skip quoted string.
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(c == '"');
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (1) {
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                NSRange escapedCharacterOrStringEnd = [string rangeOfCharacterFromSet:quotedStringCharacters options:0 range:remaining];
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (escapedCharacterOrStringEnd.location == NSNotFound) {
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                c = [string characterAtIndex:escapedCharacterOrStringEnd.location];
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                remaining.location = NSMaxRange(escapedCharacterOrStringEnd);
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                remaining.length = stringLength - remaining.location;
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // If we are the end of the string, then break from the string loop back to the host name loop.
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (c == '"') {
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    break;
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Skip escaped character.
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                ASSERT(c == '\\');
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (remaining.length == 0) {
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                remaining.location += 1;
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                remaining.length -= 1;
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void applyHostNameFunctionToURLString(NSString *string, StringRangeApplierFunction f, void *context)
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find hostnames. Too bad we can't use any real URL-parsing code to do this,
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // but we have to do it before doing all the %-escaping, and this is the only
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // code we have that parses mailto URLs anyway.
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Maybe we should implement this using a character buffer instead?
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([string _webkit_hasCaseInsensitivePrefix:@"mailto:"]) {
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        applyHostNameFunctionToMailToURLString(string, f, context);
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find the host name in a hierarchical URL.
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // It comes after a "://" sequence, with scheme characters preceding.
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If ends with the end of the string or a ":", "/", or a "?".
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If there is a "@" character, the host part is just the part after the "@".
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSRange separatorRange = [string rangeOfString:@"://"];
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (separatorRange.location == NSNotFound) {
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check that all characters before the :// are valid scheme characters.
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *nonSchemeCharacters;
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nonSchemeCharacters == nil) {
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        nonSchemeCharacters = [[NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-."] invertedSet];
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFRetain(nonSchemeCharacters);
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([string rangeOfCharacterFromSet:nonSchemeCharacters options:0 range:NSMakeRange(0, separatorRange.location)].location != NSNotFound) {
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned stringLength = [string length];
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *hostTerminators;
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hostTerminators == nil) {
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostTerminators = [NSCharacterSet characterSetWithCharactersInString:@":/?#"];
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFRetain(hostTerminators);
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Start after the separator.
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned authorityStart = NSMaxRange(separatorRange);
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find terminating character.
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSRange hostNameTerminator = [string rangeOfCharacterFromSet:hostTerminators options:0 range:NSMakeRange(authorityStart, stringLength - authorityStart)];
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned hostNameEnd = hostNameTerminator.location == NSNotFound ? stringLength : hostNameTerminator.location;
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find "@" for the start of the host name.
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSRange userInfoTerminator = [string rangeOfString:@"@" options:0 range:NSMakeRange(authorityStart, hostNameEnd - authorityStart)];
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned hostNameStart = userInfoTerminator.location == NSNotFound ? authorityStart : NSMaxRange(userInfoTerminator);
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    f(string, NSMakeRange(hostNameStart, hostNameEnd - hostNameStart), context);
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project@implementation NSURL (WebNSURLExtras)
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void collectRangesThatNeedMapping(NSString *string, NSRange range, void *context, BOOL encode)
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BOOL needsMapping = encode
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ? [string _web_hostNameNeedsEncodingWithRange:range]
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        : [string _web_hostNameNeedsDecodingWithRange:range];
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!needsMapping) {
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableArray **array = (NSMutableArray **)context;
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (*array == nil) {
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *array = [[NSMutableArray alloc] init];
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [*array addObject:[NSValue valueWithRange:range]];
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void collectRangesThatNeedEncoding(NSString *string, NSRange range, void *context)
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return collectRangesThatNeedMapping(string, range, context, YES);
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void collectRangesThatNeedDecoding(NSString *string, NSRange range, void *context)
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return collectRangesThatNeedMapping(string, range, context, NO);
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic NSString *mapHostNames(NSString *string, BOOL encode)
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Generally, we want to optimize for the case where there is one host name that does not need mapping.
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (encode && [string canBeConvertedToEncoding:NSASCIIStringEncoding])
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return string;
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Make a list of ranges that actually need mapping.
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableArray *hostNameRanges = nil;
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    StringRangeApplierFunction f = encode
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ? collectRangesThatNeedEncoding
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        : collectRangesThatNeedDecoding;
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    applyHostNameFunctionToURLString(string, f, &hostNameRanges);
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hostNameRanges == nil)
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return string;
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Do the mapping.
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableString *mutableCopy = [string mutableCopy];
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned i = [hostNameRanges count];
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (i-- != 0) {
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange hostNameRange = [[hostNameRanges objectAtIndex:i] rangeValue];
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSString *mappedHostName = encode
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ? [string _web_encodeHostNameWithRange:hostNameRange]
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            : [string _web_decodeHostNameWithRange:hostNameRange];
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [mutableCopy replaceCharactersInRange:hostNameRange withString:mappedHostName];
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [hostNameRanges release];
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [mutableCopy autorelease];
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSURL *)_web_URLWithUserTypedString:(NSString *)string relativeToURL:(NSURL *)URL
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (string == nil) {
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    string = mapHostNames([string _webkit_stringByTrimmingWhitespace], YES);
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *userTypedData = [string dataUsingEncoding:NSUTF8StringEncoding];
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(userTypedData);
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const UInt8 *inBytes = static_cast<const UInt8 *>([userTypedData bytes]);
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int inLength = [userTypedData length];
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (inLength == 0) {
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return [NSURL URLWithString:@""];
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char *outBytes = static_cast<char *>(malloc(inLength * 3)); // large enough to %-escape every character
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char *p = outBytes;
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int outLength = 0;
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < inLength; i++) {
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UInt8 c = inBytes[i];
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c <= 0x20 || c >= 0x7f) {
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = '%';
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = hexDigit(c >> 4);
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = hexDigit(c & 0xf);
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            outLength += 3;
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = c;
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            outLength++;
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *data = [NSData dataWithBytesNoCopy:outBytes length:outLength]; // adopts outBytes
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_URLWithData:data relativeToURL:URL];
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSURL *)_web_URLWithUserTypedString:(NSString *)string
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_URLWithUserTypedString:string relativeToURL:nil];
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSURL *)_web_URLWithDataAsString:(NSString *)string
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (string == nil) {
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_URLWithDataAsString:string relativeToURL:nil];
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSURL *)_web_URLWithDataAsString:(NSString *)string relativeToURL:(NSURL *)baseURL
4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (string == nil) {
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    string = [string _webkit_stringByTrimmingWhitespace];
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *data = [string dataUsingEncoding:NSISOLatin1StringEncoding];
4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_URLWithData:data relativeToURL:baseURL];
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSURL *)_web_URLWithData:(NSData *)data
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [NSURL _web_URLWithData:data relativeToURL:nil];
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSURL *)_web_URLWithData:(NSData *)data relativeToURL:(NSURL *)baseURL
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (data == nil)
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
4298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURL *result = nil;
4318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    size_t length = [data length];
4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (length > 0) {
4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // work around <rdar://4470771>: CFURLCreateAbsoluteURLWithBytes(.., TRUE) doesn't remove non-path components.
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        baseURL = [baseURL _webkit_URLByRemovingResourceSpecifier];
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UInt8 *bytes = static_cast<const UInt8*>([data bytes]);
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // NOTE: We use UTF-8 here since this encoding is used when computing strings when returning URL components
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // (e.g calls to NSURL -path). However, this function is not tolerant of illegal UTF-8 sequences, which
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // could either be a malformed string or bytes in a different encoding, like shift-jis, so we fall back
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // onto using ISO Latin 1 in those cases.
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result = WebCFAutorelease(CFURLCreateAbsoluteURLWithBytes(NULL, bytes, length, kCFStringEncodingUTF8, (CFURLRef)baseURL, YES));
4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!result)
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            result = WebCFAutorelease(CFURLCreateAbsoluteURLWithBytes(NULL, bytes, length, kCFStringEncodingISOLatin1, (CFURLRef)baseURL, YES));
4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result = [NSURL URLWithString:@""];
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSData *)_web_originalData
4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UInt8 *buffer = (UInt8 *)malloc(URL_BYTES_BUFFER_LENGTH);
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex bytesFilled = CFURLGetBytes((CFURLRef)self, buffer, URL_BYTES_BUFFER_LENGTH);
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (bytesFilled == -1) {
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFIndex bytesToAllocate = CFURLGetBytes((CFURLRef)self, NULL, 0);
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer = (UInt8 *)realloc(buffer, bytesToAllocate);
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bytesFilled = CFURLGetBytes((CFURLRef)self, buffer, bytesToAllocate);
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(bytesFilled == bytesToAllocate);
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // buffer is adopted by the NSData
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *data = [NSData dataWithBytesNoCopy:buffer length:bytesFilled freeWhenDone:YES];
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURL *baseURL = (NSURL *)CFURLGetBaseURL((CFURLRef)self);
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (baseURL)
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return [[NSURL _web_URLWithData:data relativeToURL:baseURL] _web_originalData];
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return data;
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_originalDataAsString
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[[NSString alloc] initWithData:[self _web_originalData] encoding:NSISOLatin1StringEncoding] autorelease];
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic CFStringRef createStringWithEscapedUnsafeCharacters(CFStringRef string)
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex length = CFStringGetLength(string);
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar, 2048> sourceBuffer(length);
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFStringGetCharacters(string, CFRangeMake(0, length), sourceBuffer.data());
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar, 2048> outBuffer;
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex i = 0;
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (i < length) {
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar32 c;
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        U16_NEXT(sourceBuffer, i, length, c)
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isLookalikeCharacter(c)) {
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            uint8_t utf8Buffer[4];
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CFIndex offset = 0;
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            UBool failure = false;
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            U8_APPEND(utf8Buffer, offset, 4, c, failure)
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(!failure);
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            for (CFIndex j = 0; j < offset; ++j) {
4968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                outBuffer.append('%');
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                outBuffer.append(hexDigit(utf8Buffer[j] >> 4));
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                outBuffer.append(hexDigit(utf8Buffer[j] & 0xf));
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
5018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            UChar utf16Buffer[2];
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CFIndex offset = 0;
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            UBool failure = false;
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            U16_APPEND(utf16Buffer, offset, 2, c, failure)
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(!failure);
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            for (CFIndex j = 0; j < offset; ++j)
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                outBuffer.append(utf16Buffer[j]);
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return CFStringCreateWithCharacters(NULL, outBuffer.data(), outBuffer.size());
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_userVisibleString
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *data = [self _web_originalData];
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned char *before = static_cast<const unsigned char*>([data bytes]);
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int length = [data length];
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool needsHostNameDecoding = false;
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned char *p = before;
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int bufferLength = (length * 3) + 1;
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char *after = static_cast<char *>(malloc(bufferLength)); // large enough to %-escape every character
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char *q = after;
5268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < length; i++) {
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = p[i];
5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // unescape escape sequences that indicate bytes greater than 0x7f
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '%' && (i + 1 < length && isHexDigit(p[i + 1])) && i + 2 < length && isHexDigit(p[i + 2])) {
5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            unsigned char u = (hexDigitValue(p[i + 1]) << 4) | hexDigitValue(p[i + 2]);
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (u > 0x7f) {
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // unescape
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = u;
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // do not unescape
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = p[i];
5388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = p[i + 1];
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = p[i + 2];
5408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            i += 2;
5428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *q++ = c;
5448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Check for "xn--" in an efficient, non-case-sensitive, way.
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (c == '-' && i >= 3 && !needsHostNameDecoding && (q[-4] | 0x20) == 'x' && (q[-3] | 0x20) == 'n' && q[-2] == '-')
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                needsHostNameDecoding = true;
5488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *q = '\0';
5518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check string to see if it can be converted to display using UTF-8
5538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *result = [NSString stringWithUTF8String:after];
5548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!result) {
5558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Could not convert to UTF-8.
5568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Convert characters greater than 0x7f to escape sequences.
5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Shift current string to the end of the buffer
5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // then we will copy back bytes to the start of the buffer
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // as we convert.
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int afterlength = q - after;
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char *p = after + bufferLength - afterlength - 1;
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memmove(p, after, afterlength + 1); // copies trailing '\0'
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char *q = after;
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (*p) {
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            unsigned char c = *p;
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (c > 0x7f) {
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = '%';
5688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = hexDigit(c >> 4);
5698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = hexDigit(c & 0xf);
5708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
5718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *q++ = *p;
5728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p++;
5748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *q = '\0';
5768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result = [NSString stringWithUTF8String:after];
5778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    free(after);
5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result = mapHostNames(result, !needsHostNameDecoding);
582563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    result = [result precomposedStringWithCanonicalMapping];
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return WebCFAutorelease(createStringWithEscapedUnsafeCharacters((CFStringRef)result));
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_web_isEmpty
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!CFURLGetBaseURL((CFURLRef)self))
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return CFURLGetBytes((CFURLRef)self, NULL, 0) == 0;
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self _web_originalData] length] == 0;
5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (const char *)_web_URLCString
5948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableData *data = [NSMutableData data];
5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [data appendData:[self _web_originalData]];
5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [data appendBytes:"\0" length:1];
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (const char *)[data bytes];
5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project }
6008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSURL *)_webkit_canonicalize
6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:self];
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Class concreteClass = WKNSURLProtocolClassForRequest(request);
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!concreteClass) {
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [request release];
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This applies NSURL's concept of canonicalization, but not KURL's concept. It would
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sense to apply both, but when we tried that it caused a performance degradation
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // (see 5315926). It might make sense to apply only the KURL concept and not the NSURL
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // concept, but it's too risky to make that change for WebKit 3.0.
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURLRequest *newRequest = [concreteClass canonicalRequestForRequest:request];
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURL *newURL = [newRequest URL];
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURL *result = [[newURL retain] autorelease];
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [request release];
6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
622231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block- (NSURL *)_web_URLByTruncatingOneCharacterBeforeComponent:(CFURLComponentType)component
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFRange fragRg = CFURLGetByteRangeForComponent((CFURLRef)self, component, NULL);
6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fragRg.location == kCFNotFound)
6268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UInt8 *urlBytes, buffer[2048];
6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex numBytes = CFURLGetBytes((CFURLRef)self, buffer, 2048);
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (numBytes == -1) {
6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        numBytes = CFURLGetBytes((CFURLRef)self, NULL, 0);
6328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        urlBytes = static_cast<UInt8*>(malloc(numBytes));
6338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFURLGetBytes((CFURLRef)self, urlBytes, numBytes);
6348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
6358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        urlBytes = buffer;
6368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURL *result = (NSURL *)CFMakeCollectable(CFURLCreateWithBytes(NULL, urlBytes, fragRg.location - 1, kCFStringEncodingUTF8, NULL));
6388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!result)
6398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result = (NSURL *)CFMakeCollectable(CFURLCreateWithBytes(NULL, urlBytes, fragRg.location - 1, kCFStringEncodingISOLatin1, NULL));
6408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (urlBytes != buffer) free(urlBytes);
6428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result ? [result autorelease] : self;
6438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSURL *)_webkit_URLByRemovingFragment
6468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
647231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return [self _web_URLByTruncatingOneCharacterBeforeComponent:kCFURLComponentFragment];
6488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSURL *)_webkit_URLByRemovingResourceSpecifier
6518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
652231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return [self _web_URLByTruncatingOneCharacterBeforeComponent:kCFURLComponentResourceSpecifier];
653231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
654231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
655231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block- (NSURL *)_web_URLByRemovingComponentAndSubsequentCharacter:(CFURLComponentType)component
656231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
657231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CFRange range = CFURLGetByteRangeForComponent((CFURLRef)self, component, 0);
658231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (range.location == kCFNotFound)
659231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return self;
660231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
661231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Remove one subsequent character.
662231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ++range.length;
663231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
664231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    UInt8* urlBytes;
665231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    UInt8 buffer[2048];
666231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CFIndex numBytes = CFURLGetBytes((CFURLRef)self, buffer, 2048);
667231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (numBytes == -1) {
668231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        numBytes = CFURLGetBytes((CFURLRef)self, NULL, 0);
669231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        urlBytes = static_cast<UInt8*>(malloc(numBytes));
670231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CFURLGetBytes((CFURLRef)self, urlBytes, numBytes);
671231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    } else
672231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        urlBytes = buffer;
673231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
674231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (numBytes < range.location)
675231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return self;
676231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (numBytes < range.location + range.length)
677231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        range.length = numBytes - range.location;
678231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
679231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    memmove(urlBytes + range.location, urlBytes + range.location + range.length, numBytes - range.location + range.length);
680231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
681231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    NSURL *result = (NSURL *)CFMakeCollectable(CFURLCreateWithBytes(NULL, urlBytes, numBytes - range.length, kCFStringEncodingUTF8, NULL));
682231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!result)
683231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        result = (NSURL *)CFMakeCollectable(CFURLCreateWithBytes(NULL, urlBytes, numBytes - range.length, kCFStringEncodingISOLatin1, NULL));
684231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
685231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (urlBytes != buffer)
686231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        free(urlBytes);
687231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
688231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return result ? [result autorelease] : self;
689231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
690231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
691231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block- (NSURL *)_web_URLByRemovingUserInfo
692231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
693231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return [self _web_URLByRemovingComponentAndSubsequentCharacter:kCFURLComponentUserInfo];
6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isJavaScriptURL
6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self _web_originalDataAsString] _webkit_isJavaScriptURL];
6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_scriptIfJavaScriptURL
7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self absoluteString] _webkit_scriptIfJavaScriptURL];
7048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isFileURL
7078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self _web_originalDataAsString] _webkit_isFileURL];
7098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isFTPDirectoryURL
7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self _web_originalDataAsString] _webkit_isFTPDirectoryURL];
7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_shouldLoadAsEmptyDocument
7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self _web_originalDataAsString] _webkit_hasCaseInsensitivePrefix:@"about:"] || [self _web_isEmpty];
7198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSURL *)_web_URLWithLowercasedScheme
7228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFRange range;
7248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFURLGetByteRangeForComponent((CFURLRef)self, kCFURLComponentScheme, &range);
7258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (range.location == kCFNotFound) {
7268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
7278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UInt8 static_buffer[URL_BYTES_BUFFER_LENGTH];
7308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UInt8 *buffer = static_buffer;
7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex bytesFilled = CFURLGetBytes((CFURLRef)self, buffer, URL_BYTES_BUFFER_LENGTH);
7328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (bytesFilled == -1) {
7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFIndex bytesToAllocate = CFURLGetBytes((CFURLRef)self, NULL, 0);
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer = static_cast<UInt8 *>(malloc(bytesToAllocate));
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bytesFilled = CFURLGetBytes((CFURLRef)self, buffer, bytesToAllocate);
7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(bytesFilled == bytesToAllocate);
7378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
7408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BOOL changed = NO;
7418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < range.length; ++i) {
7428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char c = buffer[range.location + i];
7438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char lower = toASCIILower(c);
7448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c != lower) {
7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            buffer[range.location + i] = lower;
7468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            changed = YES;
7478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSURL *result = changed
7518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ? (NSURL *)WebCFAutorelease(CFURLCreateAbsoluteURLWithBytes(NULL, buffer, bytesFilled, kCFStringEncodingUTF8, nil, YES))
7528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        : (NSURL *)self;
7538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (buffer != static_buffer) {
7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        free(buffer);
7568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
7598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(BOOL)_web_hasQuestionMarkOnlyQueryString
7638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFRange rangeWithSeparators;
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFURLGetByteRangeForComponent((CFURLRef)self, kCFURLComponentQuery, &rangeWithSeparators);
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (rangeWithSeparators.location != kCFNotFound && rangeWithSeparators.length == 1) {
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return YES;
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return NO;
7708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSData *)_web_schemeSeparatorWithoutColon
7738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *result = nil;
7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFRange rangeWithSeparators;
7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFRange range = CFURLGetByteRangeForComponent((CFURLRef)self, kCFURLComponentScheme, &rangeWithSeparators);
7778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (rangeWithSeparators.location != kCFNotFound) {
7788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSString *absoluteString = [self absoluteString];
7798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange separatorsRange = NSMakeRange(range.location + range.length + 1, rangeWithSeparators.length - range.length - 1);
7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (separatorsRange.location + separatorsRange.length <= [absoluteString length]) {
7818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            NSString *slashes = [absoluteString substringWithRange:separatorsRange];
7828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            result = [slashes dataUsingEncoding:NSISOLatin1StringEncoding];
7838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
7848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define completeURL (CFURLComponentType)-1
7898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSData *)_web_dataForURLComponentType:(CFURLComponentType)componentType
7918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static int URLComponentTypeBufferLength = 2048;
7938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UInt8 staticAllBytesBuffer[URLComponentTypeBufferLength];
7958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UInt8 *allBytesBuffer = staticAllBytesBuffer;
7968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFIndex bytesFilled = CFURLGetBytes((CFURLRef)self, allBytesBuffer, URLComponentTypeBufferLength);
7988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (bytesFilled == -1) {
7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFIndex bytesToAllocate = CFURLGetBytes((CFURLRef)self, NULL, 0);
8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        allBytesBuffer = static_cast<UInt8 *>(malloc(bytesToAllocate));
8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bytesFilled = CFURLGetBytes((CFURLRef)self, allBytesBuffer, bytesToAllocate);
8028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFRange range;
8058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (componentType != completeURL) {
8068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        range = CFURLGetByteRangeForComponent((CFURLRef)self, componentType, NULL);
8078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (range.location == kCFNotFound) {
8088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return nil;
8098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
8128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        range.location = 0;
8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        range.length = bytesFilled;
8148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *componentData = [NSData dataWithBytes:allBytesBuffer + range.location length:range.length];
8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned char *bytes = static_cast<const unsigned char *>([componentData bytes]);
8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableData *resultData = [NSMutableData data];
8208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // NOTE: add leading '?' to query strings non-zero length query strings.
8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // NOTE: retain question-mark only query strings.
8228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (componentType == kCFURLComponentQuery) {
8238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (range.length > 0 || [self _web_hasQuestionMarkOnlyQueryString]) {
8248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [resultData appendBytes:"?" length:1];
8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
8288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < range.length; i++) {
8298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = bytes[i];
8308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c <= 0x20 || c >= 0x7f) {
8318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            char escaped[3];
8328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            escaped[0] = '%';
8338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            escaped[1] = hexDigit(c >> 4);
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            escaped[2] = hexDigit(c & 0xf);
8358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [resultData appendBytes:escaped length:3];
8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
8388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            char b[1];
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            b[0] = c;
8408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [resultData appendBytes:b length:1];
8418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (staticAllBytesBuffer != allBytesBuffer) {
8458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        free(allBytesBuffer);
8468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return resultData;
8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSData *)_web_schemeData
8528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_dataForURLComponentType:kCFURLComponentScheme];
8548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSData *)_web_hostData
8578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *result = [self _web_dataForURLComponentType:kCFURLComponentHost];
8598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *scheme = [self _web_schemeData];
8608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Take off localhost for file
8618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([scheme _web_isCaseInsensitiveEqualToCString:"file"]) {
8628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return ([result _web_isCaseInsensitiveEqualToCString:"localhost"]) ? nil : result;
8638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
8658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_hostString
8688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSData *data = [self _web_hostData];
8708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!data) {
8718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        data = [NSData data];
8728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[[NSString alloc] initWithData:[self _web_hostData] encoding:NSUTF8StringEncoding] autorelease];
8748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_suggestedFilenameWithMIMEType:(NSString *)MIMEType
8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return suggestedFilenameWithMIMEType(self, MIMEType);
8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project@end
8828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project@implementation NSString (WebNSURLExtras)
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_web_isUserVisibleURL
8868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BOOL valid = YES;
8888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // get buffer
8898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char static_buffer[1024];
8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char *p;
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BOOL success = CFStringGetCString((CFStringRef)self, static_buffer, 1023, kCFStringEncodingUTF8);
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (success) {
8948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = static_buffer;
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = [self UTF8String];
8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int length = strlen(p);
9008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // check for characters <= 0x20 or >=0x7f, %-escape sequences of %7f, and xn--, these
9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // are the things that will lead _web_userVisibleString to actually change things.
9038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
9048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < length; i++) {
9058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = p[i];
9068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // escape control characters, space, and delete
9078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c <= 0x20 || c == 0x7f) {
9088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            valid = NO;
9098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
9108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else if (c == '%' && (i + 1 < length && isHexDigit(p[i + 1])) && i + 2 < length && isHexDigit(p[i + 2])) {
9118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            unsigned char u = (hexDigitValue(p[i + 1]) << 4) | hexDigitValue(p[i + 2]);
9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (u > 0x7f) {
9138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                valid = NO;
9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                break;
9158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            i += 2;
9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Check for "xn--" in an efficient, non-case-sensitive, way.
9198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (c == '-' && i >= 3 && (p[i - 3] | 0x20) == 'x' && (p[i - 2] | 0x20) == 'n' && p[i - 1] == '-') {
9208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                valid = NO;
9218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                break;
9228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
9238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return valid;
9278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isJavaScriptURL
9318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _webkit_hasCaseInsensitivePrefix:@"javascript:"];
9338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isFileURL
9368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self rangeOfString:@"file:" options:(NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound;
9388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_stringByReplacingValidPercentEscapes
9418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(self);
9438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_scriptIfJavaScriptURL
9468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (![self _webkit_isJavaScriptURL]) {
9488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
9498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self substringFromIndex:11] _webkit_stringByReplacingValidPercentEscapes];
9518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isFTPDirectoryURL
9548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int length = [self length];
9568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (length < 5) {  // 5 is length of "ftp:/"
9578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return NO;
9588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unichar lastChar = [self characterAtIndex:length - 1];
9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return lastChar == '/' && [self _webkit_hasCaseInsensitivePrefix:@"ftp:"];
9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic BOOL readIDNScriptWhiteListFile(NSString *filename)
9658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!filename) {
9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return NO;
9688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FILE *file = fopen([filename fileSystemRepresentation], "r");
9708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (file == NULL) {
9718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return NO;
9728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Read a word at a time.
9758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Allow comments, starting with # character to the end of the line.
9768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
9778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Skip a comment if present.
9788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int result = fscanf(file, " #%*[^\n\r]%*[\n\r]");
9798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (result == EOF) {
9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Read a script name if present.
9848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char word[33];
9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result = fscanf(file, " %32[^# \t\n\r]%*[^# \t\n\r] ", word);
9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (result == EOF) {
9878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
9888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (result == 1) {
9908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Got a word, map to script code and put it into the array.
9918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int32_t script = u_getPropertyValueEnum(UCHAR_SCRIPT, word);
9928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (script >= 0 && script < USCRIPT_CODE_LIMIT) {
9938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                size_t index = script / 32;
9948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                uint32_t mask = 1 << (script % 32);
9958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                IDNScriptWhiteList[index] |= mask;
9968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
9978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    fclose(file);
10008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return YES;
10018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void readIDNScriptWhiteList(void)
10048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Read white list from library.
10068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES);
10078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i, numDirs = [dirs count];
10088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < numDirs; i++) {
10098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSString *dir = [dirs objectAtIndex:i];
10108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (readIDNScriptWhiteListFile([dir stringByAppendingPathComponent:@"IDNScriptWhiteList.txt"])) {
10118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
10128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Fall back on white list inside bundle.
10168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit"];
10178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    readIDNScriptWhiteListFile([bundle pathForResource:@"IDNScriptWhiteList" ofType:@"txt"]);
10188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic BOOL allCharactersInIDNScriptWhiteList(const UChar *buffer, int32_t length)
10218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    pthread_once(&IDNScriptWhiteListFileRead, readIDNScriptWhiteList);
10238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int32_t i = 0;
10258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (i < length) {
10268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar32 c;
10278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        U16_NEXT(buffer, i, length, c)
10288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UErrorCode error = U_ZERO_ERROR;
10298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UScriptCode script = uscript_getScript(c, &error);
10308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (error != U_ZERO_ERROR) {
10318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            LOG_ERROR("got ICU error while trying to look at scripts: %d", error);
10328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
10338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (script < 0) {
10358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            LOG_ERROR("got negative number for script code from ICU: %d", script);
10368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
10378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (script >= USCRIPT_CODE_LIMIT) {
10398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
10408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        size_t index = script / 32;
10428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        uint32_t mask = 1 << (script % 32);
10438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!(IDNScriptWhiteList[index] & mask)) {
10448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
10458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isLookalikeCharacter(c))
10488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
10498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return YES;
10518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10536c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic BOOL allCharactersAllowedByTLDRules(const UChar* buffer, int32_t length)
10546c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
10556c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // Skip trailing dot for root domain.
10566c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (buffer[length - 1] == '.')
10576c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        --length;
10586c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
10596c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (length > 3
10606c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        && buffer[length - 3] == '.'
10616c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        && buffer[length - 2] == 0x0440 // CYRILLIC SMALL LETTER ER
10626c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        && buffer[length - 1] == 0x0444) // CYRILLIC SMALL LETTER EF
10636c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    {
10646c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        // Rules defined by <http://www.cctld.ru/ru/docs/rulesrf.php>. This code only checks requirements that matter for presentation purposes.
10656c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        for (int32_t i = length - 4; i; --i) {
10666c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            UChar ch = buffer[i];
10676c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
10686c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            // Only modern Russian letters, digits and dashes are allowed.
10696c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            if ((ch >= 0x0430 && ch <= 0x044f)
10706c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                || ch == 0x0451
10716c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                || (ch >= '0' && ch <= '9')
10726c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                || ch == '-')
10736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                continue;
10746c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
10756c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            // Only check top level domain. Lower level registrars may have different rules.
10766c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            if (ch == '.')
10776c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                break;
10786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
10796c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            return NO;
10806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        }
10816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return YES;
10826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
10836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
10846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // Not a known top level domain with special rules.
10856c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    return NO;
10866c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
10876c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
10888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Return value of nil means no mapping is necessary.
10898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// If makeString is NO, then return value is either nil or self to indicate mapping is necessary.
10908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// If makeString is YES, then return value is either nil or the mapped string.
10918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_mapHostNameWithRange:(NSRange)range encode:(BOOL)encode makeString:(BOOL)makeString
10928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (range.length > HOST_NAME_BUFFER_LENGTH) {
10948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
10958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([self length] == 0)
10988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
10998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UChar sourceBuffer[HOST_NAME_BUFFER_LENGTH];
11018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UChar destinationBuffer[HOST_NAME_BUFFER_LENGTH];
11028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *string = self;
11048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (encode && [self rangeOfString:@"%" options:NSLiteralSearch range:range].location != NSNotFound) {
11058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSString *substring = [self substringWithRange:range];
11068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        substring = WebCFAutorelease(CFURLCreateStringByReplacingPercentEscapes(NULL, (CFStringRef)substring, CFSTR("")));
11078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (substring != nil) {
11088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            string = substring;
11098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            range = NSMakeRange(0, [string length]);
11108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
11118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int length = range.length;
11148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [string getCharacters:sourceBuffer range:range];
11158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UErrorCode error = U_ZERO_ERROR;
11178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int32_t numCharactersConverted = (encode ? uidna_IDNToASCII : uidna_IDNToUnicode)
11188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        (sourceBuffer, length, destinationBuffer, HOST_NAME_BUFFER_LENGTH, UIDNA_ALLOW_UNASSIGNED, NULL, &error);
11198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (error != U_ZERO_ERROR) {
11208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
11218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (numCharactersConverted == length && memcmp(sourceBuffer, destinationBuffer, length * sizeof(UChar)) == 0) {
11238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
11248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11256c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (!encode && !allCharactersInIDNScriptWhiteList(destinationBuffer, numCharactersConverted) && !allCharactersAllowedByTLDRules(destinationBuffer, numCharactersConverted)) {
11268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
11278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return makeString ? (NSString *)[NSString stringWithCharacters:destinationBuffer length:numCharactersConverted] : (NSString *)self;
11298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_web_hostNameNeedsDecodingWithRange:(NSRange)range
11328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_mapHostNameWithRange:range encode:NO makeString:NO] != nil;
11348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_web_hostNameNeedsEncodingWithRange:(NSRange)range
11378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_mapHostNameWithRange:range encode:YES makeString:NO] != nil;
11398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_decodeHostNameWithRange:(NSRange)range
11428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_mapHostNameWithRange:range encode:NO makeString:YES];
11448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_encodeHostNameWithRange:(NSRange)range
11478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self _web_mapHostNameWithRange:range encode:YES makeString:YES];
11498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_decodeHostName
11528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *name = [self _web_mapHostNameWithRange:NSMakeRange(0, [self length]) encode:NO makeString:YES];
11548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return name == nil ? self : name;
11558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_encodeHostName
11588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *name = [self _web_mapHostNameWithRange:NSMakeRange(0, [self length]) encode:YES makeString:YES];
11608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return name == nil ? self : name;
11618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSRange)_webkit_rangeOfURLScheme
11648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSRange colon = [self rangeOfString:@":"];
11668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (colon.location != NSNotFound && colon.location > 0) {
11678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange scheme = {0, colon.location};
11688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        static NSCharacterSet *InverseSchemeCharacterSet = nil;
11698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!InverseSchemeCharacterSet) {
11708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            /*
11718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project             This stuff is very expensive.  10-15 msec on a 2x1.2GHz.  If not cached it swamps
11728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project             everything else when adding items to the autocomplete DB.  Makes me wonder if we
11738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project             even need to enforce the character set here.
11748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            */
11758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            NSString *acceptableCharacters = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+.-";
11768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            InverseSchemeCharacterSet = [[[NSCharacterSet characterSetWithCharactersInString:acceptableCharacters] invertedSet] retain];
11778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
11788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange illegals = [self rangeOfCharacterFromSet:InverseSchemeCharacterSet options:0 range:scheme];
11798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (illegals.location == NSNotFound)
11808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return scheme;
11818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return NSMakeRange(NSNotFound, 0);
11838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(BOOL)_webkit_looksLikeAbsoluteURL
11868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Trim whitespace because _web_URLWithString allows whitespace.
11888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [[self _webkit_stringByTrimmingWhitespace] _webkit_rangeOfURLScheme].location != NSNotFound;
11898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_URLFragment
11928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSRange fragmentRange;
11948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    fragmentRange = [self rangeOfString:@"#" options:NSLiteralSearch];
11968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fragmentRange.location == NSNotFound)
11978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return nil;
11988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self substringFromIndex:fragmentRange.location + 1];
11998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
12008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project@end
1202