void nsCSSScanner::ParseAndAppendEscape(nsString& aOutput) { PRInt32 ch = Peek(); if (ch < 0) { aOutput.Append(CSS_ESCAPE); return; } if (IsHexDigit(ch)) { PRInt32 rv = 0; int i; for (i = 0; i < 6; i++) { // up to six digits ch = Read(); if (ch < 0) { // Whoops: error or premature eof break; } if (!IsHexDigit(ch) && !IsWhitespace(ch)) { Pushback(ch); break; } else if (IsHexDigit(ch)) { rv = rv * 16 + HexDigitValue(ch); } else { NS_ASSERTION(IsWhitespace(ch), "bad control flow"); // single space ends escape break; } } if (6 == i) { // look for trailing whitespace and eat it ch = Peek(); if (IsWhitespace(ch)) { (void) Read(); } } NS_ASSERTION(rv >= 0, "How did rv become negative?"); // "[at most six hexadecimal digits following a backslash] stand // for the ISO 10646 character with that number, which must not be // zero. (It is undefined in CSS 2.1 what happens if a style sheet // does contain a character with Unicode codepoint zero.)" // -- CSS2.1 section 4.1.3 // // Silently deleting \0 opens a content-filtration loophole (see // bug 228856), so what we do instead is pretend the "cancels the // meaning of special characters" rule applied. if (rv > 0) { AppendUCS4ToUTF16(ENSURE_VALID_CHAR(rv), aOutput); } else { while (i--) aOutput.Append('0'); if (IsWhitespace(ch)) Pushback(ch); } return; } // "Any character except a hexidecimal digit can be escaped to // remove its special meaning by putting a backslash in front" // -- CSS1 spec section 7.1 ch = Read(); // Consume the escaped character if ((ch > 0) && (ch != '\n')) { aOutput.Append(ch); } }
/** * If there is a valid escape sequence starting at the current read * position, consume it, decode it, append the result to |aOutput|, * and return true. Otherwise, consume nothing, leave |aOutput| * unmodified, and return false. If |aInString| is true, accept the * additional form of escape sequence allowed within string-like tokens. */ bool nsCSSScanner::GatherEscape(nsString& aOutput, bool aInString) { MOZ_ASSERT(Peek() == '\\', "should not have been called"); int32_t ch = Peek(1); if (ch < 0) { // If we are in a string (or a url() containing a string), we want to drop // the backslash on the floor. Otherwise, we want to treat it as a U+FFFD // character. Advance(); if (aInString) { SetEOFCharacters(eEOFCharacters_DropBackslash); } else { aOutput.Append(UCS2_REPLACEMENT_CHAR); SetEOFCharacters(eEOFCharacters_ReplacementChar); } return true; } if (IsVertSpace(ch)) { if (aInString) { // In strings (and in url() containing a string), escaped // newlines are completely removed, to allow splitting over // multiple lines. Advance(); AdvanceLine(); return true; } // Outside of strings, backslash followed by a newline is not an escape. return false; } if (!IsHexDigit(ch)) { // "Any character (except a hexadecimal digit, linefeed, carriage // return, or form feed) can be escaped with a backslash to remove // its special meaning." -- CSS2.1 section 4.1.3 Advance(2); if (ch == 0) { aOutput.Append(UCS2_REPLACEMENT_CHAR); } else { aOutput.Append(ch); } return true; } // "[at most six hexadecimal digits following a backslash] stand // for the ISO 10646 character with that number, which must not be // zero. (It is undefined in CSS 2.1 what happens if a style sheet // does contain a character with Unicode codepoint zero.)" // -- CSS2.1 section 4.1.3 // At this point we know we have \ followed by at least one // hexadecimal digit, therefore the escape sequence is valid and we // can go ahead and consume the backslash. Advance(); uint32_t val = 0; int i = 0; do { val = val * 16 + HexDigitValue(ch); i++; Advance(); ch = Peek(); } while (i < 6 && IsHexDigit(ch)); // "Interpret the hex digits as a hexadecimal number. If this number is zero, // or is greater than the maximum allowed codepoint, return U+FFFD // REPLACEMENT CHARACTER" -- CSS Syntax Level 3 if (MOZ_UNLIKELY(val == 0)) { aOutput.Append(UCS2_REPLACEMENT_CHAR); } else { AppendUCS4ToUTF16(ENSURE_VALID_CHAR(val), aOutput); } // Consume exactly one whitespace character after a // hexadecimal escape sequence. if (IsVertSpace(ch)) { AdvanceLine(); } else if (IsHorzSpace(ch)) { Advance(); } return true; }
void nsCSSScanner::ParseAndAppendEscape(nsresult& aErrorCode, nsString& aOutput) { PRUint8* lexTable = gLexTable; PRInt32 ch = Peek(aErrorCode); if (ch < 0) { aOutput.Append(CSS_ESCAPE); return; } if ((ch <= 255) && ((lexTable[ch] & IS_HEX_DIGIT) != 0)) { PRInt32 rv = 0; int i; for (i = 0; i < 6; i++) { // up to six digits ch = Read(aErrorCode); if (ch < 0) { // Whoops: error or premature eof break; } if (ch >= 256 || (lexTable[ch] & (IS_HEX_DIGIT | IS_WHITESPACE)) == 0) { Unread(); break; } else if ((lexTable[ch] & IS_HEX_DIGIT) != 0) { if ((lexTable[ch] & IS_DIGIT) != 0) { rv = rv * 16 + (ch - '0'); } else { // Note: c&7 just keeps the low three bits which causes // upper and lower case alphabetics to both yield their // "relative to 10" value for computing the hex value. rv = rv * 16 + ((ch & 0x7) + 9); } } else { NS_ASSERTION((lexTable[ch] & IS_WHITESPACE) != 0, "bad control flow"); // single space ends escape if (ch == '\r' && Peek(aErrorCode) == '\n') { // if CR/LF, eat LF too Read(aErrorCode); } break; } } if (6 == i) { // look for trailing whitespace and eat it ch = Peek(aErrorCode); if ((0 <= ch) && (ch <= 255) && ((lexTable[ch] & IS_WHITESPACE) != 0)) { (void) Read(aErrorCode); // special case: if trailing whitespace is CR/LF, eat both chars. if (ch == '\r' && Peek(aErrorCode) == '\n') { (void) Read(aErrorCode); // if we hit the "\0" special case below, we'll push back // only the '\r', but that's okay, because '\r' by itself // is still a newline. } } } NS_ASSERTION(rv >= 0, "How did rv become negative?"); // "[at most six hexadecimal digits following a backslash] stand // for the ISO 10646 character with that number, which must not be // zero. (It is undefined in CSS 2.1 what happens if a style sheet // does contain a character with Unicode codepoint zero.)" // -- CSS2.1 section 4.1.3 // // Silently deleting \0 opens a content-filtration loophole (see // bug 228856), so what we do instead is pretend the "cancels the // meaning of special characters" rule applied. if (rv > 0) { AppendUCS4ToUTF16(ENSURE_VALID_CHAR(rv), aOutput); } else { while (i--) aOutput.Append('0'); if ((0 <= ch) && (ch <= 255) && ((lexTable[ch] & IS_WHITESPACE) != 0)) Pushback(ch); } return; } else { // "Any character except a hexidecimal digit can be escaped to // remove its special meaning by putting a backslash in front" // -- CSS1 spec section 7.1 if (!EatNewline(aErrorCode)) { // skip escaped newline (void) Read(aErrorCode); if (ch > 0) { aOutput.Append(ch); } } return; } }
void nsCSSScanner::ParseAndAppendEscape(nsresult& aErrorCode, nsString& aOutput) { PRInt32 ch = Peek(aErrorCode); if (ch < 0) { aOutput.Append(CSS_ESCAPE); return; } if (IsHexDigit(ch)) { PRInt32 rv = 0; int i; for (i = 0; i < 6; i++) { // up to six digits ch = Read(aErrorCode); if (ch < 0) { // Whoops: error or premature eof break; } if (!IsHexDigit(ch) && !IsWhitespace(ch)) { Pushback(ch); break; } else if (IsHexDigit(ch)) { if (IsDigit(ch)) { rv = rv * 16 + (ch - '0'); } else { // Note: c&7 just keeps the low three bits which causes // upper and lower case alphabetics to both yield their // "relative to 10" value for computing the hex value. rv = rv * 16 + ((ch & 0x7) + 9); } } else { NS_ASSERTION(IsWhitespace(ch), "bad control flow"); // single space ends escape break; } } if (6 == i) { // look for trailing whitespace and eat it ch = Peek(aErrorCode); if (IsWhitespace(ch)) { (void) Read(aErrorCode); } } NS_ASSERTION(rv >= 0, "How did rv become negative?"); // "[at most six hexadecimal digits following a backslash] stand // for the ISO 10646 character with that number, which must not be // zero. (It is undefined in CSS 2.1 what happens if a style sheet // does contain a character with Unicode codepoint zero.)" // -- CSS2.1 section 4.1.3 // // Silently deleting \0 opens a content-filtration loophole (see // bug 228856), so what we do instead is pretend the "cancels the // meaning of special characters" rule applied. if (rv > 0) { AppendUCS4ToUTF16(ENSURE_VALID_CHAR(rv), aOutput); } else { while (i--) aOutput.Append('0'); if (IsWhitespace(ch)) Pushback(ch); } return; } else { // "Any character except a hexidecimal digit can be escaped to // remove its special meaning by putting a backslash in front" // -- CSS1 spec section 7.1 if (!EatNewline(aErrorCode)) { // skip escaped newline (void) Read(aErrorCode); if (ch > 0) { aOutput.Append(ch); } } return; } }