/* * Copyright (c) 2013, Opera Software ASA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Opera Software ASA nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VTTScanner_h #define VTTScanner_h #include "ParsingUtilities.h" #include namespace WebCore { // Helper class for "scanning" an input string and performing parsing of // "micro-syntax"-like constructs. // // There's two primary operations: match and scan. // // The 'match' operation matches an explicitly or implicitly specified sequence // against the characters ahead of the current input pointer, and returns true // if the sequence can be matched. // // The 'scan' operation performs a 'match', and if the match is successful it // advance the input pointer past the matched sequence. class VTTScanner { WTF_MAKE_NONCOPYABLE(VTTScanner); public: explicit VTTScanner(const String& line); typedef const LChar* Position; class Run { public: Run(Position start, Position end, bool is8Bit) : m_start(start), m_end(end), m_is8Bit(is8Bit) { } Position start() const { return m_start; } Position end() const { return m_end; } bool isEmpty() const { return m_start == m_end; } size_t length() const; private: Position m_start; Position m_end; bool m_is8Bit; }; // Check if the input pointer points at the specified position. bool isAt(Position checkPosition) const { return position() == checkPosition; } // Check if the input pointer points at the end of the input. bool isAtEnd() const { return position() == end(); } // Match the character |c| against the character at the input pointer (~lookahead). bool match(char c) const { return !isAtEnd() && currentChar() == c; } // Scan the character |c|. bool scan(char); // Scan the first |charactersCount| characters of the string |characters|. bool scan(const LChar* characters, size_t charactersCount); // Scan the literal |characters|. template bool scan(const char (&characters)[charactersCount]); // Skip (advance the input pointer) as long as the specified // |characterPredicate| returns true, and the input pointer is not passed // the end of the input. template void skipWhile(); // Like skipWhile, but using a negated predicate. template void skipUntil(); // Return the run of characters for which the specified // |characterPredicate| returns true. The start of the run will be the // current input pointer. template Run collectWhile(); // Like collectWhile, but using a negated predicate. template Run collectUntil(); // Scan the string |toMatch|, using the specified |run| as the sequence to // match against. bool scanRun(const Run&, const String& toMatch); // Skip to the end of the specified |run|. void skipRun(const Run&); // Return the String made up of the characters in |run|, and advance the // input pointer to the end of the run. String extractString(const Run&); // Return a String constructed from the rest of the input (between input // pointer and end of input), and advance the input pointer accordingly. String restOfInputAsString(); // Scan a set of ASCII digits from the input. Return the number of digits // scanned, and set |number| to the computed value. If the digits make up a // number that does not fit the 'int' type, |number| is set to INT_MAX. // Note: Does not handle sign. unsigned scanDigits(int& number); // Scan a floating point value on one of the forms: \d+\.? \d+\.\d+ \.\d+ bool scanFloat(float& number, bool* isNegative = nullptr); protected: Position position() const { return m_data.characters8; } Position end() const { return m_end.characters8; } void seekTo(Position); UChar currentChar() const; void advance(unsigned amount = 1); // Adapt a UChar-predicate to an LChar-predicate. // (For use with skipWhile/Until from ParsingUtilities.h). template static inline bool LCharPredicateAdapter(LChar c) { return characterPredicate(c); } union { const LChar* characters8; const UChar* characters16; } m_data; union { const LChar* characters8; const UChar* characters16; } m_end; bool m_is8Bit; }; inline size_t VTTScanner::Run::length() const { if (m_is8Bit) return m_end - m_start; return reinterpret_cast(m_end) - reinterpret_cast(m_start); } template inline bool VTTScanner::scan(const char (&characters)[charactersCount]) { return scan(reinterpret_cast(characters), charactersCount - 1); } template inline void VTTScanner::skipWhile() { if (m_is8Bit) ::skipWhile >(m_data.characters8, m_end.characters8); else ::skipWhile(m_data.characters16, m_end.characters16); } template inline void VTTScanner::skipUntil() { if (m_is8Bit) ::skipUntil >(m_data.characters8, m_end.characters8); else ::skipUntil(m_data.characters16, m_end.characters16); } template inline VTTScanner::Run VTTScanner::collectWhile() { if (m_is8Bit) { const LChar* current = m_data.characters8; ::skipWhile >(current, m_end.characters8); return Run(position(), current, m_is8Bit); } const UChar* current = m_data.characters16; ::skipWhile(current, m_end.characters16); return Run(position(), reinterpret_cast(current), m_is8Bit); } template inline VTTScanner::Run VTTScanner::collectUntil() { if (m_is8Bit) { const LChar* current = m_data.characters8; ::skipUntil >(current, m_end.characters8); return Run(position(), current, m_is8Bit); } const UChar* current = m_data.characters16; ::skipUntil(current, m_end.characters16); return Run(position(), reinterpret_cast(current), m_is8Bit); } inline void VTTScanner::seekTo(Position position) { ASSERT(position <= end()); m_data.characters8 = position; } inline UChar VTTScanner::currentChar() const { ASSERT(position() < end()); return m_is8Bit ? *m_data.characters8 : *m_data.characters16; } inline void VTTScanner::advance(unsigned amount) { ASSERT(position() < end()); if (m_is8Bit) m_data.characters8 += amount; else m_data.characters16 += amount; } } #endif