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