int moIStream::Get(wchar_t& c) { int r; r = Read(&c, sizeof(wchar_t)); if(r != sizeof(wchar_t)) { if(r > 0) { Unread(&c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER) { if(sizeof(wchar_t) == 2) { c = moSwap16Bits((uint16_t) c); } else if(sizeof(wchar_t) == 4) { c = moSwap32Bits((uint32_t) c); } else { throw moError("FATAL ERROR: don't know how to swap a 'wchar_t'.\n"); } } return r; }
/************************************************************ DOC: CLASS moIStream NAME Get - read a value from the input stream SYNOPSIS virtual int Get(<type>& c); where <type> is any one of the C++ integer and floating point type (bool, char, wchar_t, short, int, long, long long, float, double, long double -- integers have signed and an unsigned versions.) PARAMETERS c - a reference where the data read is written DESCRIPTION The Get() functions will read the necessary number of bytes from the input stream using the Read() function and return the resulting value. By default, the endian of the input stream is assumed to be the same as the system being used. It can be changed with the SetInputEndianess() function. Though these are defined as virtual, they don't need to be overridden in your own stream declaration if it isn't to make it any faster. RETURN VALUE the number of bytes read (1, 2, 4 or 8 at this time) -1 when an error occurs BUGS On some systems the size of some C++ types won't be properly recognized and thus an error will be thrown. This should never happen though. SEE ALSO Unget(), moOStream::Put(), SetInputEndianess() */ int moIStream::Get(bool& c) { int r; bool* p_c = &c; r = Read(p_c, sizeof(bool)); if(r != sizeof(bool)) { if(r > 0) { Unread(p_c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER && sizeof(bool) != 1) { if(sizeof(bool) == 2) { uint16_t *ptr = reinterpret_cast<uint16_t *>(p_c); *ptr = moSwap16Bits(*ptr); } else if(sizeof(bool) == 4) { uint32_t *ptr = reinterpret_cast<uint32_t *>(p_c); *ptr = moSwap32Bits(*ptr); } else { throw moError("FATAL ERROR: don't know how to swap a 'bool'.\n"); } } return r; }
int moIStream::Get(unsigned long& c) { int r; r = Read(&c, sizeof(unsigned long)); if(r != sizeof(unsigned long)) { if(r > 0) { Unread(&c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER) { if(sizeof(unsigned long) == 4) { c = moSwap32Bits((uint32_t) c); } else if(sizeof(unsigned long) == 8) { c = moSwap64Bits((uint64_t) c); } else { throw moError("FATAL ERROR: don't know how to swap a 'long'.\n"); } } return r; }
int moIStream::Unget(uint64_t c) { if(f_input_endian != BYTE_ORDER) { c = moSwap64Bits(c); } return Unread(&c, sizeof(uint64_t)); }
int moIStream::Unget(float c) { float* p_c = &c; if(f_input_endian != BYTE_ORDER) { // we assume that float is 32 bits int32_t *ptr = reinterpret_cast<int32_t *>(p_c); *ptr = moSwap32Bits(*ptr); } return Unread(p_c, sizeof(float)); }
int moIStream::Unget(double c) { double* p_c = &c; if(f_input_endian != BYTE_ORDER) { // we assume that double is 64 bits int64_t *ptr = reinterpret_cast<int64_t *>(p_c); *ptr = moSwap64Bits(*ptr); } return Unread(p_c, sizeof(double)); }
PRBool nsCSSScanner::LookAhead(nsresult& aErrorCode, PRUnichar aChar) { PRInt32 ch = Read(aErrorCode); if (ch < 0) { return PR_FALSE; } if (ch == aChar) { return PR_TRUE; } Unread(); return PR_FALSE; }
int moIStream::Unget(long double c) { int64_t a, b; long double * p_c = &c; if(f_input_endian != BYTE_ORDER) { // we assume that double is 64 bits a = moSwap64Bits(reinterpret_cast<int64_t *>(p_c)[0]); b = moSwap64Bits(reinterpret_cast<int64_t *>(p_c)[1]); reinterpret_cast<int64_t *>(p_c)[0] = b; reinterpret_cast<int64_t *>(p_c)[1] = a; } return Unread(p_c, sizeof(long double)); }
int moIStream::Get(unsigned char& c) { int r; r = Read(&c, sizeof(unsigned char)); if(r != sizeof(unsigned char)) { if(r > 0) { Unread(&c, r); return 0; } return r; } return r; }
int moIStream::Unget(unsigned long c) { if(f_input_endian != BYTE_ORDER) { if(sizeof(unsigned long) == 4) { c = moSwap32Bits((uint32_t) c); } else if(sizeof(unsigned long) == 8) { c = moSwap64Bits((uint64_t) c); } else { throw moError("FATAL ERROR: don't know how to swap a 'long'.\n"); } } return Unread(&c, sizeof(unsigned long)); }
int moIStream::Unget(wchar_t c) { if(f_input_endian != BYTE_ORDER) { if(sizeof(wchar_t) == 2) { c = moSwap16Bits((uint16_t) c); } else if(sizeof(wchar_t) == 4) { c = moSwap32Bits((uint32_t) c); } else { throw moError("FATAL ERROR: don't know how to swap a 'wchar_t'.\n"); } } return Unread(&c, sizeof(wchar_t)); }
PRBool nsCSSScanner::EatWhiteSpace(nsresult& aErrorCode) { PRBool eaten = PR_FALSE; for (;;) { PRInt32 ch = Read(aErrorCode); if (ch < 0) { break; } if ((ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t')) { eaten = PR_TRUE; continue; } Unread(); break; } return eaten; }
int moIStream::Get(uint64_t& c) { int r; r = Read(&c, sizeof(uint64_t)); if(r != sizeof(uint64_t)) { if(r > 0) { Unread(&c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER) { c = moSwap64Bits(c); } return r; }
PRBool nsCSSScanner::EatNewline(nsresult& aErrorCode) { PRInt32 ch = Read(aErrorCode); if (ch < 0) { return PR_FALSE; } PRBool eaten = PR_FALSE; if (ch == '\r') { eaten = PR_TRUE; ch = Peek(aErrorCode); if (ch == '\n') { (void) Read(aErrorCode); } } else if (ch == '\n') { eaten = PR_TRUE; } else { Unread(); } return eaten; }
int moIStream::Get(double& c) { int r; double* p_c = &c; r = Read(p_c, sizeof(double)); if(r != sizeof(double)) { if(r > 0) { Unread(p_c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER) { int64_t *ptr = reinterpret_cast<int64_t *>(p_c); *ptr = moSwap64Bits(*ptr); } return r; }
int moIStream::Get(float& c) { int r; float* p_c = &c; r = Read(p_c, sizeof(float)); if(r != sizeof(float)) { if(r > 0) { Unread(p_c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER) { int32_t *ptr = reinterpret_cast<int32_t *>(p_c); *ptr = moSwap32Bits(*ptr); } return r; }
int moIStream::Get(long double& c) { int r; int64_t a, b; r = Read(&c, sizeof(long double)); if(r != sizeof(long double)) { if(r > 0) { Unread(&c, r); return 0; } return r; } if(f_input_endian != BYTE_ORDER) { a = moSwap64Bits(((int64_t *) &c)[0]); b = moSwap64Bits(((int64_t *) &c)[1]); ((int64_t *) &c)[0] = b; ((int64_t *) &c)[1] = a; } return r; }
/** * Gather up the characters in an identifier. The identfier was * started by "aChar" which will be appended to aIdent. The result * will be aIdent with all of the identifier characters appended * until the first non-identifier character is seen. The termination * character is unread for the future re-reading. */ PRBool nsCSSScanner::GatherIdent(nsresult& aErrorCode, PRInt32 aChar, nsString& aIdent) { if (aChar == CSS_ESCAPE) { ParseAndAppendEscape(aErrorCode, aIdent); } else if (0 < aChar) { aIdent.Append(aChar); } for (;;) { aChar = Read(aErrorCode); if (aChar < 0) break; if (aChar == CSS_ESCAPE) { ParseAndAppendEscape(aErrorCode, aIdent); } else if ((aChar > 255) || ((gLexTable[aChar] & IS_IDENT) != 0)) { aIdent.Append(PRUnichar(aChar)); } else { Unread(); break; } } return PR_TRUE; }
PRBool nsCSSScanner::ParseRef(nsresult& aErrorCode, PRInt32 aChar, nsCSSToken& aToken) { aToken.mIdent.SetLength(0); aToken.mType = eCSSToken_Ref; PRInt32 ch = Read(aErrorCode); if (ch < 0) { return PR_FALSE; } if (ch > 255 || (gLexTable[ch] & IS_IDENT) || ch == CSS_ESCAPE) { // First char after the '#' is a valid ident char (or an escape), // so it makes sense to keep going if (StartsIdent(ch, Peek(aErrorCode), gLexTable)) { aToken.mType = eCSSToken_ID; } return GatherIdent(aErrorCode, ch, aToken.mIdent); } // No ident chars after the '#'. Just unread |ch| and get out of here. Unread(); return PR_TRUE; }
PRBool nsCSSScanner::NextURL(nsresult& aErrorCode, nsCSSToken& aToken) { PRInt32 ch = Read(aErrorCode); if (ch < 0) { return PR_FALSE; } if (ch < 256) { PRUint8* lexTable = gLexTable; // STRING if ((ch == '"') || (ch == '\'')) { return ParseString(aErrorCode, ch, aToken); } // WS if ((lexTable[ch] & IS_WHITESPACE) != 0) { aToken.mType = eCSSToken_WhiteSpace; aToken.mIdent.Assign(PRUnichar(ch)); (void) EatWhiteSpace(aErrorCode); return PR_TRUE; } if (ch == '/') { PRInt32 nextChar = Peek(aErrorCode); if (nextChar == '*') { (void) Read(aErrorCode); #if 0 // If we change our storage data structures such that comments are // stored (for Editor), we should reenable this code, condition it // on being in editor mode, and apply glazou's patch from bug // 60290. aToken.mIdent.SetCapacity(2); aToken.mIdent.Assign(PRUnichar(ch)); aToken.mIdent.Append(PRUnichar(nextChar)); return ParseCComment(aErrorCode, aToken); #endif return SkipCComment(aErrorCode) && Next(aErrorCode, aToken); } } // Process a url lexical token. A CSS1 url token can contain // characters beyond identifier characters (e.g. '/', ':', etc.) // Because of this the normal rules for tokenizing the input don't // apply very well. To simplify the parser and relax some of the // requirements on the scanner we parse url's here. If we find a // malformed URL then we emit a token of type "InvalidURL" so that // the CSS1 parser can ignore the invalid input. We attempt to eat // the right amount of input data when an invalid URL is presented. aToken.mType = eCSSToken_InvalidURL; nsString& ident = aToken.mIdent; ident.SetLength(0); if (ch == ')') { Pushback(ch); // empty url spec; just get out of here aToken.mType = eCSSToken_URL; } else { // start of a non-quoted url Pushback(ch); PRBool ok = PR_TRUE; for (;;) { ch = Read(aErrorCode); if (ch < 0) break; if (ch == CSS_ESCAPE) { ParseAndAppendEscape(aErrorCode, ident); } else if ((ch == '"') || (ch == '\'') || (ch == '(')) { // This is an invalid URL spec ok = PR_FALSE; } else if ((256 > ch) && ((gLexTable[ch] & IS_WHITESPACE) != 0)) { // Whitespace is allowed at the end of the URL (void) EatWhiteSpace(aErrorCode); if (LookAhead(aErrorCode, ')')) { Pushback(')'); // leave the closing symbol // done! break; } // Whitespace is followed by something other than a // ")". This is an invalid url spec. ok = PR_FALSE; } else if (ch == ')') { Unread(); // All done break; } else { // A regular url character. ident.Append(PRUnichar(ch)); } } // If the result of the above scanning is ok then change the token // type to a useful one. if (ok) { aToken.mType = eCSSToken_URL; } } } return PR_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; } }
int moIStream::Unget(unsigned char c) { return Unread(&c, sizeof(unsigned char)); }
PRBool nsCSSScanner::ParseNumber(nsresult& aErrorCode, PRInt32 c, nsCSSToken& aToken) { nsString& ident = aToken.mIdent; ident.SetLength(0); PRBool gotDot = (c == '.') ? PR_TRUE : PR_FALSE; if (c != '+') { ident.Append(PRUnichar(c)); } // Gather up characters that make up the number PRUint8* lexTable = gLexTable; for (;;) { c = Read(aErrorCode); if (c < 0) break; if (!gotDot && (c == '.') && CheckLexTable(Peek(aErrorCode), IS_DIGIT, lexTable)) { gotDot = PR_TRUE; } else if ((c > 255) || ((lexTable[c] & IS_DIGIT) == 0)) { break; } ident.Append(PRUnichar(c)); } // Convert number to floating point nsCSSTokenType type = eCSSToken_Number; PRInt32 ec; float value = ident.ToFloat(&ec); // Look at character that terminated the number aToken.mIntegerValid = PR_FALSE; if (c >= 0) { if ((c <= 255) && ((lexTable[c] & START_IDENT) != 0)) { ident.SetLength(0); if (!GatherIdent(aErrorCode, c, ident)) { return PR_FALSE; } type = eCSSToken_Dimension; } else if ('%' == c) { type = eCSSToken_Percentage; value = value / 100.0f; ident.SetLength(0); } else { // Put back character that stopped numeric scan Unread(); if (!gotDot) { aToken.mInteger = ident.ToInteger(&ec); aToken.mIntegerValid = PR_TRUE; } ident.SetLength(0); } } else { // stream ended if (!gotDot) { aToken.mInteger = ident.ToInteger(&ec); aToken.mIntegerValid = PR_TRUE; } ident.SetLength(0); } aToken.mNumber = value; aToken.mType = type; return PR_TRUE; }