static inline int HexNibbleValue( const char* c ) { int h = HexDigitValue( c[0] ); if ( h < 0 ) return -1; int l = HexDigitValue( c[1] ); if ( l < 0 ) return -1; return (h << 4) + l; }
int HexStrToInt64(const char *string, uint64_t *dest){ while(*string!='\0'){ if(!IsHexDigit(*string)) return -1; dest[0]<<=4; dest[0]+=HexDigitValue(*string); string++; } return 1; }
PRBool nsCSSScanner::ParseURange(PRInt32 aChar, nsCSSToken& aResult) { PRInt32 intro2 = Read(); PRInt32 ch = Peek(); // We should only ever be called if these things are true. NS_ASSERTION(aChar == 'u' || aChar == 'U', "unicode-range called with improper introducer (U)"); NS_ASSERTION(intro2 == '+', "unicode-range called with improper introducer (+)"); // If the character immediately after the '+' is not a hex digit or // '?', this is not really a unicode-range token; push everything // back and scan the U as an ident. if (!IsHexDigit(ch) && ch != '?') { Pushback(intro2); Pushback(aChar); return ParseIdent(aChar, aResult); } aResult.mIdent.Truncate(); aResult.mIdent.Append(aChar); aResult.mIdent.Append(intro2); PRBool valid = PR_TRUE; PRBool haveQues = PR_FALSE; PRUint32 low = 0; PRUint32 high = 0; int i = 0; for (;;) { ch = Read(); i++; if (i == 7 || !(IsHexDigit(ch) || ch == '?')) { break; } aResult.mIdent.Append(ch); if (IsHexDigit(ch)) { if (haveQues) { valid = PR_FALSE; // all question marks should be at the end } low = low*16 + HexDigitValue(ch); high = high*16 + HexDigitValue(ch); } else { haveQues = PR_TRUE; low = low*16 + 0x0; high = high*16 + 0xF; } } if (ch == '-' && IsHexDigit(Peek())) { if (haveQues) { valid = PR_FALSE; } aResult.mIdent.Append(ch); high = 0; i = 0; for (;;) { ch = Read(); i++; if (i == 7 || !IsHexDigit(ch)) { break; } aResult.mIdent.Append(ch); high = high*16 + HexDigitValue(ch); } } Pushback(ch); aResult.mInteger = low; aResult.mInteger2 = high; aResult.mIntegerValid = valid; aResult.mType = eCSSToken_URange; return PR_TRUE; }
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; }
/** * Scan a unicode-range token. These match the regular expression * * u\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})? * * However, some such tokens are "invalid". There are three valid forms: * * u+[0-9a-f]{x} 1 <= x <= 6 * u+[0-9a-f]{x}\?{y} 1 <= x+y <= 6 * u+[0-9a-f]{x}-[0-9a-f]{y} 1 <= x <= 6, 1 <= y <= 6 * * All unicode-range tokens have their text recorded in mIdent; valid ones * are also decoded into mInteger and mInteger2, and mIntegerValid is set. * Note that this does not validate the numeric range, only the syntactic * form. */ bool nsCSSScanner::ScanURange(nsCSSToken& aResult) { int32_t intro1 = Peek(); int32_t intro2 = Peek(1); int32_t ch = Peek(2); MOZ_ASSERT((intro1 == 'u' || intro1 == 'U') && intro2 == '+' && (IsHexDigit(ch) || ch == '?'), "should not have been called"); aResult.mIdent.Append(intro1); aResult.mIdent.Append(intro2); Advance(2); bool valid = true; bool haveQues = false; uint32_t low = 0; uint32_t high = 0; int i = 0; do { aResult.mIdent.Append(ch); if (IsHexDigit(ch)) { if (haveQues) { valid = false; // All question marks should be at the end. } low = low*16 + HexDigitValue(ch); high = high*16 + HexDigitValue(ch); } else { haveQues = true; low = low*16 + 0x0; high = high*16 + 0xF; } i++; Advance(); ch = Peek(); } while (i < 6 && (IsHexDigit(ch) || ch == '?')); if (ch == '-' && IsHexDigit(Peek(1))) { if (haveQues) { valid = false; } aResult.mIdent.Append(ch); Advance(); ch = Peek(); high = 0; i = 0; do { aResult.mIdent.Append(ch); high = high*16 + HexDigitValue(ch); i++; Advance(); ch = Peek(); } while (i < 6 && IsHexDigit(ch)); } aResult.mInteger = low; aResult.mInteger2 = high; aResult.mIntegerValid = valid; aResult.mType = eCSSToken_URange; return true; }