/* * Copyright (C) 2010 Google, Inc. 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. */ #pragma once #include "SegmentedString.h" #include namespace WebCore { // The InputStream is made up of a sequence of SegmentedStrings: // // [--current--][--next--][--next--] ... [--next--] // /\ (also called m_last) // L_ current insertion point // // The current segmented string is stored in InputStream. Each of the // afterInsertionPoint buffers are stored in InsertionPointRecords on the // stack. // // We remove characters from the "current" string in the InputStream. // document.write() will add characters at the current insertion point, // which appends them to the "current" string. // // m_last is a pointer to the last of the afterInsertionPoint strings. // The network adds data at the end of the InputStream, which appends // them to the "last" string. class HTMLInputStream { WTF_MAKE_NONCOPYABLE(HTMLInputStream); public: HTMLInputStream() : m_last(&m_first) { } void appendToEnd(SegmentedString&& string) { m_last->append(WTFMove(string)); } void insertAtCurrentInsertionPoint(SegmentedString&& string) { m_first.append(WTFMove(string)); } bool hasInsertionPoint() const { return &m_first != m_last; } void markEndOfFile() { m_last->append(String { &kEndOfFileMarker, 1 }); m_last->close(); } void closeWithoutMarkingEndOfFile() { m_last->close(); } bool haveSeenEndOfFile() const { return m_last->isClosed(); } SegmentedString& current() { return m_first; } const SegmentedString& current() const { return m_first; } void splitInto(SegmentedString& next) { next = WTFMove(m_first); if (m_last == &m_first) { // We used to only have one SegmentedString in the InputStream // but now we have two. That means m_first is no longer also // the m_last string, |next| is now the last one. m_last = &next; } } void mergeFrom(SegmentedString& next) { m_first.append(next); if (m_last == &next) { // The string |next| used to be the last SegmentedString in // the InputStream. Now that it's been merged into m_first, // that makes m_first the last one. m_last = &m_first; } if (next.isClosed()) { // We also need to merge the "closed" state from next to // m_first. Arguably, this work could be done in append(). m_first.close(); } } private: SegmentedString m_first; SegmentedString* m_last; }; class InsertionPointRecord { WTF_MAKE_NONCOPYABLE(InsertionPointRecord); public: explicit InsertionPointRecord(HTMLInputStream& inputStream) : m_inputStream(&inputStream) { m_line = m_inputStream->current().currentLine(); m_column = m_inputStream->current().currentColumn(); m_inputStream->splitInto(m_next); // We 'fork' current position and use it for the generated script part. // This is a bit weird, because generated part does not have positions within an HTML document. m_inputStream->current().setCurrentPosition(m_line, m_column, 0); } ~InsertionPointRecord() { // Some inserted text may have remained in input stream. E.g. if script has written "&" or "current().length(); m_inputStream->mergeFrom(m_next); // We restore position for the character that goes right after unparsed remainder. m_inputStream->current().setCurrentPosition(m_line, m_column, unparsedRemainderLength); } private: HTMLInputStream* m_inputStream; SegmentedString m_next; OrdinalNumber m_line; OrdinalNumber m_column; }; } // namespace WebCore