| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/escape.h" | 5 #include "net/base/escape.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 // Lastly, we can't unescape anything that doesn't have a canonical | 78 // Lastly, we can't unescape anything that doesn't have a canonical |
| 79 // representation in a URL. This means that unescaping will change the URL, and | 79 // representation in a URL. This means that unescaping will change the URL, and |
| 80 // you could get different behavior if you copy and paste the URL, or press | 80 // you could get different behavior if you copy and paste the URL, or press |
| 81 // enter in the URL bar. The list of characters that fall into this category | 81 // enter in the URL bar. The list of characters that fall into this category |
| 82 // are the ones labeled PASS (allow either escaped or unescaped) in the big | 82 // are the ones labeled PASS (allow either escaped or unescaped) in the big |
| 83 // lookup table at the top of url/url_canon_path.cc. Also, characters | 83 // lookup table at the top of url/url_canon_path.cc. Also, characters |
| 84 // that have CHAR_QUERY set in url/url_canon_internal.cc but are not | 84 // that have CHAR_QUERY set in url/url_canon_internal.cc but are not |
| 85 // allowed in query strings according to http://www.ietf.org/rfc/rfc3261.txt are | 85 // allowed in query strings according to http://www.ietf.org/rfc/rfc3261.txt are |
| 86 // not unescaped, to avoid turning a valid url according to spec into an | 86 // not unescaped, to avoid turning a valid url according to spec into an |
| 87 // invalid one. | 87 // invalid one. |
| 88 // clang-format off |
| 88 const char kUrlUnescape[128] = { | 89 const char kUrlUnescape[128] = { |
| 89 // NULL, control chars... | 90 // NULL, control chars... |
| 90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 92 // ' ' ! " # $ % & ' ( ) * + , - . / | 93 // ' ' ! " # $ % & ' ( ) * + , - . / |
| 93 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, | 94 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, |
| 94 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | 95 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? |
| 95 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, | 96 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, |
| 96 // @ A B C D E F G H I J K L M N O | 97 // @ A B C D E F G H I J K L M N O |
| 97 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 98 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 98 // P Q R S T U V W X Y Z [ \ ] ^ _ | 99 // P Q R S T U V W X Y Z [ \ ] ^ _ |
| 99 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, | 100 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, |
| 100 // ` a b c d e f g h i j k l m n o | 101 // ` a b c d e f g h i j k l m n o |
| 101 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 102 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 102 // p q r s t u v w x y z { | } ~ <NBSP> | 103 // p q r s t u v w x y z { | } ~ <NBSP> |
| 103 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 | 104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 |
| 104 }; | 105 }; |
| 106 // clang-format on |
| 105 | 107 |
| 106 // Attempts to unescape the sequence at |index| within |escaped_text|. If | 108 // Attempts to unescape the sequence at |index| within |escaped_text|. If |
| 107 // successful, sets |value| to the unescaped value. Returns whether | 109 // successful, sets |value| to the unescaped value. Returns whether |
| 108 // unescaping succeeded. | 110 // unescaping succeeded. |
| 109 template<typename STR> | 111 template <typename STR> |
| 110 bool UnescapeUnsignedCharAtIndex(const STR& escaped_text, | 112 bool UnescapeUnsignedCharAtIndex(const STR& escaped_text, |
| 111 size_t index, | 113 size_t index, |
| 112 unsigned char* value) { | 114 unsigned char* value) { |
| 113 if ((index + 2) >= escaped_text.size()) | 115 if ((index + 2) >= escaped_text.size()) |
| 114 return false; | 116 return false; |
| 115 if (escaped_text[index] != '%') | 117 if (escaped_text[index] != '%') |
| 116 return false; | 118 return false; |
| 117 const typename STR::value_type most_sig_digit( | 119 const typename STR::value_type most_sig_digit( |
| 118 static_cast<typename STR::value_type>(escaped_text[index + 1])); | 120 static_cast<typename STR::value_type>(escaped_text[index + 1])); |
| 119 const typename STR::value_type least_sig_digit( | 121 const typename STR::value_type least_sig_digit( |
| 120 static_cast<typename STR::value_type>(escaped_text[index + 2])); | 122 static_cast<typename STR::value_type>(escaped_text[index + 2])); |
| 121 if (IsHexDigit(most_sig_digit) && IsHexDigit(least_sig_digit)) { | 123 if (IsHexDigit(most_sig_digit) && IsHexDigit(least_sig_digit)) { |
| 122 *value = HexDigitToInt(most_sig_digit) * 16 + | 124 *value = |
| 123 HexDigitToInt(least_sig_digit); | 125 HexDigitToInt(most_sig_digit) * 16 + HexDigitToInt(least_sig_digit); |
| 124 return true; | 126 return true; |
| 125 } | 127 } |
| 126 return false; | 128 return false; |
| 127 } | 129 } |
| 128 | 130 |
| 129 // Returns true if there is an Arabic Language Mark at |index|. |first_byte| | 131 // Returns true if there is an Arabic Language Mark at |index|. |first_byte| |
| 130 // is the byte at |index|. | 132 // is the byte at |index|. |
| 131 template<typename STR> | 133 template <typename STR> |
| 132 bool HasArabicLanguageMarkAtIndex(const STR& escaped_text, | 134 bool HasArabicLanguageMarkAtIndex(const STR& escaped_text, |
| 133 unsigned char first_byte, | 135 unsigned char first_byte, |
| 134 size_t index) { | 136 size_t index) { |
| 135 if (first_byte != 0xD8) | 137 if (first_byte != 0xD8) |
| 136 return false; | 138 return false; |
| 137 unsigned char second_byte; | 139 unsigned char second_byte; |
| 138 if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 3, &second_byte)) | 140 if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 3, &second_byte)) |
| 139 return false; | 141 return false; |
| 140 return second_byte == 0x9c; | 142 return second_byte == 0x9c; |
| 141 } | 143 } |
| 142 | 144 |
| 143 // Returns true if there is a BiDi control char at |index|. |first_byte| is the | 145 // Returns true if there is a BiDi control char at |index|. |first_byte| is the |
| 144 // byte at |index|. | 146 // byte at |index|. |
| 145 template<typename STR> | 147 template <typename STR> |
| 146 bool HasThreeByteBidiControlCharAtIndex(const STR& escaped_text, | 148 bool HasThreeByteBidiControlCharAtIndex(const STR& escaped_text, |
| 147 unsigned char first_byte, | 149 unsigned char first_byte, |
| 148 size_t index) { | 150 size_t index) { |
| 149 if (first_byte != 0xE2) | 151 if (first_byte != 0xE2) |
| 150 return false; | 152 return false; |
| 151 unsigned char second_byte; | 153 unsigned char second_byte; |
| 152 if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 3, &second_byte)) | 154 if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 3, &second_byte)) |
| 153 return false; | 155 return false; |
| 154 if (second_byte != 0x80 && second_byte != 0x81) | 156 if (second_byte != 0x80 && second_byte != 0x81) |
| 155 return false; | 157 return false; |
| 156 unsigned char third_byte; | 158 unsigned char third_byte; |
| 157 if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 6, &third_byte)) | 159 if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 6, &third_byte)) |
| 158 return false; | 160 return false; |
| 159 if (second_byte == 0x80) { | 161 if (second_byte == 0x80) { |
| 160 return third_byte == 0x8E || | 162 return third_byte == 0x8E || third_byte == 0x8F || |
| 161 third_byte == 0x8F || | |
| 162 (third_byte >= 0xAA && third_byte <= 0xAE); | 163 (third_byte >= 0xAA && third_byte <= 0xAE); |
| 163 } | 164 } |
| 164 return third_byte >= 0xA6 && third_byte <= 0xA9; | 165 return third_byte >= 0xA6 && third_byte <= 0xA9; |
| 165 } | 166 } |
| 166 | 167 |
| 167 // Unescapes |escaped_text| according to |rules|, returning the resulting | 168 // Unescapes |escaped_text| according to |rules|, returning the resulting |
| 168 // string. Fills in an |adjustments| parameter, if non-NULL, so it reflects | 169 // string. Fills in an |adjustments| parameter, if non-NULL, so it reflects |
| 169 // the alterations done to the string that are not one-character-to-one- | 170 // the alterations done to the string that are not one-character-to-one- |
| 170 // character. The resulting |adjustments| will always be sorted by increasing | 171 // character. The resulting |adjustments| will always be sorted by increasing |
| 171 // offset. | 172 // offset. |
| 172 template<typename STR> | 173 template <typename STR> |
| 173 STR UnescapeURLWithAdjustmentsImpl( | 174 STR UnescapeURLWithAdjustmentsImpl( |
| 174 const STR& escaped_text, | 175 const STR& escaped_text, |
| 175 UnescapeRule::Type rules, | 176 UnescapeRule::Type rules, |
| 176 base::OffsetAdjuster::Adjustments* adjustments) { | 177 base::OffsetAdjuster::Adjustments* adjustments) { |
| 177 if (adjustments) | 178 if (adjustments) |
| 178 adjustments->clear(); | 179 adjustments->clear(); |
| 179 // Do not unescape anything, return the |escaped_text| text. | 180 // Do not unescape anything, return the |escaped_text| text. |
| 180 if (rules == UnescapeRule::NONE) | 181 if (rules == UnescapeRule::NONE) |
| 181 return escaped_text; | 182 return escaped_text; |
| 182 | 183 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 | 269 |
| 269 return result; | 270 return result; |
| 270 } | 271 } |
| 271 | 272 |
| 272 template <class str> | 273 template <class str> |
| 273 void AppendEscapedCharForHTMLImpl(typename str::value_type c, str* output) { | 274 void AppendEscapedCharForHTMLImpl(typename str::value_type c, str* output) { |
| 274 static const struct { | 275 static const struct { |
| 275 char key; | 276 char key; |
| 276 const char* replacement; | 277 const char* replacement; |
| 277 } kCharsToEscape[] = { | 278 } kCharsToEscape[] = { |
| 278 { '<', "<" }, | 279 {'<', "<"}, |
| 279 { '>', ">" }, | 280 {'>', ">"}, |
| 280 { '&', "&" }, | 281 {'&', "&"}, |
| 281 { '"', """ }, | 282 {'"', """}, |
| 282 { '\'', "'" }, | 283 {'\'', "'"}, |
| 283 }; | 284 }; |
| 284 size_t k; | 285 size_t k; |
| 285 for (k = 0; k < arraysize(kCharsToEscape); ++k) { | 286 for (k = 0; k < arraysize(kCharsToEscape); ++k) { |
| 286 if (c == kCharsToEscape[k].key) { | 287 if (c == kCharsToEscape[k].key) { |
| 287 const char* p = kCharsToEscape[k].replacement; | 288 const char* p = kCharsToEscape[k].replacement; |
| 288 while (*p) | 289 while (*p) |
| 289 output->push_back(*p++); | 290 output->push_back(*p++); |
| 290 break; | 291 break; |
| 291 } | 292 } |
| 292 } | 293 } |
| 293 if (k == arraysize(kCharsToEscape)) | 294 if (k == arraysize(kCharsToEscape)) |
| 294 output->push_back(c); | 295 output->push_back(c); |
| 295 } | 296 } |
| 296 | 297 |
| 297 template <class str> | 298 template <class str> |
| 298 str EscapeForHTMLImpl(const str& input) { | 299 str EscapeForHTMLImpl(const str& input) { |
| 299 str result; | 300 str result; |
| 300 result.reserve(input.size()); // Optimize for no escaping. | 301 result.reserve(input.size()); // Optimize for no escaping. |
| 301 | 302 |
| 302 for (typename str::const_iterator i = input.begin(); i != input.end(); ++i) | 303 for (typename str::const_iterator i = input.begin(); i != input.end(); ++i) |
| 303 AppendEscapedCharForHTMLImpl(*i, &result); | 304 AppendEscapedCharForHTMLImpl(*i, &result); |
| 304 | 305 |
| 305 return result; | 306 return result; |
| 306 } | 307 } |
| 307 | 308 |
| 308 // Everything except alphanumerics and !'()*-._~ | 309 // Everything except alphanumerics and !'()*-._~ |
| 309 // See RFC 2396 for the list of reserved characters. | 310 // See RFC 2396 for the list of reserved characters. |
| 310 static const Charmap kQueryCharmap = {{ | 311 static const Charmap kQueryCharmap = {{0xffffffffL, |
| 311 0xffffffffL, 0xfc00987dL, 0x78000001L, 0xb8000001L, | 312 0xfc00987dL, |
| 312 0xffffffffL, 0xffffffffL, 0xffffffffL, 0xffffffffL | 313 0x78000001L, |
| 313 }}; | 314 0xb8000001L, |
| 315 0xffffffffL, |
| 316 0xffffffffL, |
| 317 0xffffffffL, |
| 318 0xffffffffL}}; |
| 314 | 319 |
| 315 // non-printable, non-7bit, and (including space) "#%:<>?[\]^`{|} | 320 // non-printable, non-7bit, and (including space) "#%:<>?[\]^`{|} |
| 316 static const Charmap kPathCharmap = {{ | 321 static const Charmap kPathCharmap = {{0xffffffffL, |
| 317 0xffffffffL, 0xd400002dL, 0x78000000L, 0xb8000001L, | 322 0xd400002dL, |
| 318 0xffffffffL, 0xffffffffL, 0xffffffffL, 0xffffffffL | 323 0x78000000L, |
| 319 }}; | 324 0xb8000001L, |
| 325 0xffffffffL, |
| 326 0xffffffffL, |
| 327 0xffffffffL, |
| 328 0xffffffffL}}; |
| 320 | 329 |
| 321 // non-printable, non-7bit, and (including space) ?>=<;+'&%$#"![\]^`{|} | 330 // non-printable, non-7bit, and (including space) ?>=<;+'&%$#"![\]^`{|} |
| 322 static const Charmap kUrlEscape = {{ | 331 static const Charmap kUrlEscape = {{0xffffffffL, |
| 323 0xffffffffL, 0xf80008fdL, 0x78000001L, 0xb8000001L, | 332 0xf80008fdL, |
| 324 0xffffffffL, 0xffffffffL, 0xffffffffL, 0xffffffffL | 333 0x78000001L, |
| 325 }}; | 334 0xb8000001L, |
| 335 0xffffffffL, |
| 336 0xffffffffL, |
| 337 0xffffffffL, |
| 338 0xffffffffL}}; |
| 326 | 339 |
| 327 // non-7bit | 340 // non-7bit |
| 328 static const Charmap kNonASCIICharmap = {{ | 341 static const Charmap kNonASCIICharmap = {{0x00000000L, |
| 329 0x00000000L, 0x00000000L, 0x00000000L, 0x00000000L, | 342 0x00000000L, |
| 330 0xffffffffL, 0xffffffffL, 0xffffffffL, 0xffffffffL | 343 0x00000000L, |
| 331 }}; | 344 0x00000000L, |
| 345 0xffffffffL, |
| 346 0xffffffffL, |
| 347 0xffffffffL, |
| 348 0xffffffffL}}; |
| 332 | 349 |
| 333 // Everything except alphanumerics, the reserved characters(;/?:@&=+$,) and | 350 // Everything except alphanumerics, the reserved characters(;/?:@&=+$,) and |
| 334 // !'()*-._~#[] | 351 // !'()*-._~#[] |
| 335 static const Charmap kExternalHandlerCharmap = {{ | 352 static const Charmap kExternalHandlerCharmap = {{0xffffffffL, |
| 336 0xffffffffL, 0x50000025L, 0x50000000L, 0xb8000001L, | 353 0x50000025L, |
| 337 0xffffffffL, 0xffffffffL, 0xffffffffL, 0xffffffffL | 354 0x50000000L, |
| 338 }}; | 355 0xb8000001L, |
| 356 0xffffffffL, |
| 357 0xffffffffL, |
| 358 0xffffffffL, |
| 359 0xffffffffL}}; |
| 339 | 360 |
| 340 } // namespace | 361 } // namespace |
| 341 | 362 |
| 342 std::string EscapeQueryParamValue(const std::string& text, bool use_plus) { | 363 std::string EscapeQueryParamValue(const std::string& text, bool use_plus) { |
| 343 return Escape(text, kQueryCharmap, use_plus); | 364 return Escape(text, kQueryCharmap, use_plus); |
| 344 } | 365 } |
| 345 | 366 |
| 346 std::string EscapePath(const std::string& path) { | 367 std::string EscapePath(const std::string& path) { |
| 347 return Escape(path, kPathCharmap, false); | 368 return Escape(path, kPathCharmap, false); |
| 348 } | 369 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 UnescapeRule::Type rules) { | 406 UnescapeRule::Type rules) { |
| 386 return UnescapeAndDecodeUTF8URLComponentWithAdjustments(text, rules, NULL); | 407 return UnescapeAndDecodeUTF8URLComponentWithAdjustments(text, rules, NULL); |
| 387 } | 408 } |
| 388 | 409 |
| 389 base::string16 UnescapeAndDecodeUTF8URLComponentWithAdjustments( | 410 base::string16 UnescapeAndDecodeUTF8URLComponentWithAdjustments( |
| 390 const std::string& text, | 411 const std::string& text, |
| 391 UnescapeRule::Type rules, | 412 UnescapeRule::Type rules, |
| 392 base::OffsetAdjuster::Adjustments* adjustments) { | 413 base::OffsetAdjuster::Adjustments* adjustments) { |
| 393 base::string16 result; | 414 base::string16 result; |
| 394 base::OffsetAdjuster::Adjustments unescape_adjustments; | 415 base::OffsetAdjuster::Adjustments unescape_adjustments; |
| 395 std::string unescaped_url(UnescapeURLWithAdjustmentsImpl( | 416 std::string unescaped_url( |
| 396 text, rules, &unescape_adjustments)); | 417 UnescapeURLWithAdjustmentsImpl(text, rules, &unescape_adjustments)); |
| 397 if (base::UTF8ToUTF16WithAdjustments(unescaped_url.data(), | 418 if (base::UTF8ToUTF16WithAdjustments( |
| 398 unescaped_url.length(), | 419 unescaped_url.data(), unescaped_url.length(), &result, adjustments)) { |
| 399 &result, adjustments)) { | |
| 400 // Character set looks like it's valid. | 420 // Character set looks like it's valid. |
| 401 if (adjustments) { | 421 if (adjustments) { |
| 402 base::OffsetAdjuster::MergeSequentialAdjustments(unescape_adjustments, | 422 base::OffsetAdjuster::MergeSequentialAdjustments(unescape_adjustments, |
| 403 adjustments); | 423 adjustments); |
| 404 } | 424 } |
| 405 return result; | 425 return result; |
| 406 } | 426 } |
| 407 // Character set is not valid. Return the escaped version. | 427 // Character set is not valid. Return the escaped version. |
| 408 return base::UTF8ToUTF16WithAdjustments(text, adjustments); | 428 return base::UTF8ToUTF16WithAdjustments(text, adjustments); |
| 409 } | 429 } |
| 410 | 430 |
| 411 base::string16 UnescapeForHTML(const base::string16& input) { | 431 base::string16 UnescapeForHTML(const base::string16& input) { |
| 412 static const struct { | 432 static const struct { |
| 413 const char* ampersand_code; | 433 const char* ampersand_code; |
| 414 const char replacement; | 434 const char replacement; |
| 415 } kEscapeToChars[] = { | 435 } kEscapeToChars[] = { |
| 416 { "<", '<' }, | 436 {"<", '<'}, |
| 417 { ">", '>' }, | 437 {">", '>'}, |
| 418 { "&", '&' }, | 438 {"&", '&'}, |
| 419 { """, '"' }, | 439 {""", '"'}, |
| 420 { "'", '\''}, | 440 {"'", '\''}, |
| 421 }; | 441 }; |
| 422 | 442 |
| 423 if (input.find(base::ASCIIToUTF16("&")) == std::string::npos) | 443 if (input.find(base::ASCIIToUTF16("&")) == std::string::npos) |
| 424 return input; | 444 return input; |
| 425 | 445 |
| 426 base::string16 ampersand_chars[arraysize(kEscapeToChars)]; | 446 base::string16 ampersand_chars[arraysize(kEscapeToChars)]; |
| 427 base::string16 text(input); | 447 base::string16 text(input); |
| 428 for (base::string16::iterator iter = text.begin(); | 448 for (base::string16::iterator iter = text.begin(); iter != text.end(); |
| 429 iter != text.end(); ++iter) { | 449 ++iter) { |
| 430 if (*iter == '&') { | 450 if (*iter == '&') { |
| 431 // Potential ampersand encode char. | 451 // Potential ampersand encode char. |
| 432 size_t index = iter - text.begin(); | 452 size_t index = iter - text.begin(); |
| 433 for (size_t i = 0; i < arraysize(kEscapeToChars); i++) { | 453 for (size_t i = 0; i < arraysize(kEscapeToChars); i++) { |
| 434 if (ampersand_chars[i].empty()) { | 454 if (ampersand_chars[i].empty()) { |
| 435 ampersand_chars[i] = | 455 ampersand_chars[i] = |
| 436 base::ASCIIToUTF16(kEscapeToChars[i].ampersand_code); | 456 base::ASCIIToUTF16(kEscapeToChars[i].ampersand_code); |
| 437 } | 457 } |
| 438 if (text.find(ampersand_chars[i], index) == index) { | 458 if (text.find(ampersand_chars[i], index) == index) { |
| 439 text.replace(iter, iter + ampersand_chars[i].length(), | 459 text.replace(iter, iter + ampersand_chars[i].length(), 1, |
| 440 1, kEscapeToChars[i].replacement); | 460 kEscapeToChars[i].replacement); |
| 441 break; | 461 break; |
| 442 } | 462 } |
| 443 } | 463 } |
| 444 } | 464 } |
| 445 } | 465 } |
| 446 return text; | 466 return text; |
| 447 } | 467 } |
| 448 | 468 |
| 449 } // namespace net | 469 } // namespace net |
| OLD | NEW |