1/*
2    Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public License
15    along with this library; see the file COPYING.LIB.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17    Boston, MA 02110-1301, USA.
18*/
19
20#include "config.h"
21#include "SegmentedString.h"
22
23namespace WebCore {
24
25SegmentedString::SegmentedString(const SegmentedString& other)
26    : m_pushedChar1(other.m_pushedChar1)
27    , m_pushedChar2(other.m_pushedChar2)
28    , m_currentString(other.m_currentString)
29    , m_numberOfCharactersConsumedPriorToCurrentString(other.m_numberOfCharactersConsumedPriorToCurrentString)
30    , m_numberOfCharactersConsumedPriorToCurrentLine(other.m_numberOfCharactersConsumedPriorToCurrentLine)
31    , m_currentLine(other.m_currentLine)
32    , m_substrings(other.m_substrings)
33    , m_closed(other.m_closed)
34    , m_empty(other.m_empty)
35    , m_fastPathFlags(other.m_fastPathFlags)
36    , m_advanceFunc(other.m_advanceFunc)
37    , m_advanceAndUpdateLineNumberFunc(other.m_advanceAndUpdateLineNumberFunc)
38{
39    if (m_pushedChar2)
40        m_currentChar = m_pushedChar2;
41    else if (m_pushedChar1)
42        m_currentChar = m_pushedChar1;
43    else
44        m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
45}
46
47const SegmentedString& SegmentedString::operator=(const SegmentedString& other)
48{
49    m_pushedChar1 = other.m_pushedChar1;
50    m_pushedChar2 = other.m_pushedChar2;
51    m_currentString = other.m_currentString;
52    m_substrings = other.m_substrings;
53    if (m_pushedChar2)
54        m_currentChar = m_pushedChar2;
55    else if (m_pushedChar1)
56        m_currentChar = m_pushedChar1;
57    else
58        m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
59
60    m_closed = other.m_closed;
61    m_empty = other.m_empty;
62    m_fastPathFlags = other.m_fastPathFlags;
63    m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString;
64    m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine;
65    m_currentLine = other.m_currentLine;
66
67    m_advanceFunc = other.m_advanceFunc;
68    m_advanceAndUpdateLineNumberFunc = other.m_advanceAndUpdateLineNumberFunc;
69
70    return *this;
71}
72
73unsigned SegmentedString::length() const
74{
75    unsigned length = m_currentString.m_length;
76    if (m_pushedChar1) {
77        ++length;
78        if (m_pushedChar2)
79            ++length;
80    }
81    if (isComposite()) {
82        Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
83        Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
84        for (; it != e; ++it)
85            length += it->m_length;
86    }
87    return length;
88}
89
90void SegmentedString::setExcludeLineNumbers()
91{
92    m_currentString.setExcludeLineNumbers();
93    if (isComposite()) {
94        Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
95        Deque<SegmentedSubstring>::iterator e = m_substrings.end();
96        for (; it != e; ++it)
97            it->setExcludeLineNumbers();
98    }
99}
100
101void SegmentedString::clear()
102{
103    m_pushedChar1 = 0;
104    m_pushedChar2 = 0;
105    m_currentChar = 0;
106    m_currentString.clear();
107    m_numberOfCharactersConsumedPriorToCurrentString = 0;
108    m_numberOfCharactersConsumedPriorToCurrentLine = 0;
109    m_currentLine = 0;
110    m_substrings.clear();
111    m_closed = false;
112    m_empty = true;
113    m_fastPathFlags = NoFastPath;
114    m_advanceFunc = &SegmentedString::advanceEmpty;
115    m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
116}
117
118void SegmentedString::append(const SegmentedSubstring& s)
119{
120    ASSERT(!m_closed);
121    if (!s.m_length)
122        return;
123
124    if (!m_currentString.m_length) {
125        m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
126        m_currentString = s;
127        updateAdvanceFunctionPointers();
128    } else
129        m_substrings.append(s);
130    m_empty = false;
131}
132
133void SegmentedString::prepend(const SegmentedSubstring& s)
134{
135    ASSERT(!escaped());
136    ASSERT(!s.numberOfCharactersConsumed());
137    if (!s.m_length)
138        return;
139
140    // FIXME: We're assuming that the prepend were originally consumed by
141    //        this SegmentedString.  We're also ASSERTing that s is a fresh
142    //        SegmentedSubstring.  These assumptions are sufficient for our
143    //        current use, but we might need to handle the more elaborate
144    //        cases in the future.
145    m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
146    m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
147    if (!m_currentString.m_length) {
148        m_currentString = s;
149        updateAdvanceFunctionPointers();
150    } else {
151        // Shift our m_currentString into our list.
152        m_substrings.prepend(m_currentString);
153        m_currentString = s;
154        updateAdvanceFunctionPointers();
155    }
156    m_empty = false;
157}
158
159void SegmentedString::close()
160{
161    // Closing a stream twice is likely a coding mistake.
162    ASSERT(!m_closed);
163    m_closed = true;
164}
165
166void SegmentedString::append(const SegmentedString& s)
167{
168    ASSERT(!m_closed);
169    ASSERT(!s.escaped());
170    append(s.m_currentString);
171    if (s.isComposite()) {
172        Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
173        Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
174        for (; it != e; ++it)
175            append(*it);
176    }
177    m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
178}
179
180void SegmentedString::prepend(const SegmentedString& s)
181{
182    ASSERT(!escaped());
183    ASSERT(!s.escaped());
184    if (s.isComposite()) {
185        Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
186        Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
187        for (; it != e; ++it)
188            prepend(*it);
189    }
190    prepend(s.m_currentString);
191    m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
192}
193
194void SegmentedString::advanceSubstring()
195{
196    if (isComposite()) {
197        m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
198        m_currentString = m_substrings.takeFirst();
199        // If we've previously consumed some characters of the non-current
200        // string, we now account for those characters as part of the current
201        // string, not as part of "prior to current string."
202        m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
203        updateAdvanceFunctionPointers();
204    } else {
205        m_currentString.clear();
206        m_empty = true;
207        m_fastPathFlags = NoFastPath;
208        m_advanceFunc = &SegmentedString::advanceEmpty;
209        m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
210    }
211}
212
213String SegmentedString::toString() const
214{
215    StringBuilder result;
216    if (m_pushedChar1) {
217        result.append(m_pushedChar1);
218        if (m_pushedChar2)
219            result.append(m_pushedChar2);
220    }
221    m_currentString.appendTo(result);
222    if (isComposite()) {
223        Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
224        Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
225        for (; it != e; ++it)
226            it->appendTo(result);
227    }
228    return result.toString();
229}
230
231void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
232{
233    ASSERT_WITH_SECURITY_IMPLICATION(count <= length());
234    for (unsigned i = 0; i < count; ++i) {
235        consumedCharacters[i] = currentChar();
236        advance();
237    }
238}
239
240void SegmentedString::advance8()
241{
242    ASSERT(!m_pushedChar1);
243    decrementAndCheckLength();
244    m_currentChar = m_currentString.incrementAndGetCurrentChar8();
245}
246
247void SegmentedString::advance16()
248{
249    ASSERT(!m_pushedChar1);
250    decrementAndCheckLength();
251    m_currentChar = m_currentString.incrementAndGetCurrentChar16();
252}
253
254void SegmentedString::advanceAndUpdateLineNumber8()
255{
256    ASSERT(!m_pushedChar1);
257    ASSERT(m_currentString.getCurrentChar() == m_currentChar);
258    if (m_currentChar == '\n') {
259        ++m_currentLine;
260        m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
261    }
262    decrementAndCheckLength();
263    m_currentChar = m_currentString.incrementAndGetCurrentChar8();
264}
265
266void SegmentedString::advanceAndUpdateLineNumber16()
267{
268    ASSERT(!m_pushedChar1);
269    ASSERT(m_currentString.getCurrentChar() == m_currentChar);
270    if (m_currentChar == '\n') {
271        ++m_currentLine;
272        m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
273    }
274    decrementAndCheckLength();
275    m_currentChar = m_currentString.incrementAndGetCurrentChar16();
276}
277
278void SegmentedString::advanceSlowCase()
279{
280    if (m_pushedChar1) {
281        m_pushedChar1 = m_pushedChar2;
282        m_pushedChar2 = 0;
283
284        if (m_pushedChar1) {
285            m_currentChar = m_pushedChar1;
286            return;
287        }
288
289        updateAdvanceFunctionPointers();
290    } else if (m_currentString.m_length) {
291        if (--m_currentString.m_length == 0)
292            advanceSubstring();
293    } else if (!isComposite()) {
294        m_currentString.clear();
295        m_empty = true;
296        m_fastPathFlags = NoFastPath;
297        m_advanceFunc = &SegmentedString::advanceEmpty;
298        m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
299    }
300    m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
301}
302
303void SegmentedString::advanceAndUpdateLineNumberSlowCase()
304{
305    if (m_pushedChar1) {
306        m_pushedChar1 = m_pushedChar2;
307        m_pushedChar2 = 0;
308
309        if (m_pushedChar1) {
310            m_currentChar = m_pushedChar1;
311            return;
312        }
313
314        updateAdvanceFunctionPointers();
315    } else if (m_currentString.m_length) {
316        if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) {
317            ++m_currentLine;
318            // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
319            m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
320        }
321        if (--m_currentString.m_length == 0)
322            advanceSubstring();
323        else
324            m_currentString.incrementAndGetCurrentChar(); // Only need the ++
325    } else if (!isComposite()) {
326        m_currentString.clear();
327        m_empty = true;
328        m_fastPathFlags = NoFastPath;
329        m_advanceFunc = &SegmentedString::advanceEmpty;
330        m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
331    }
332
333    m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
334}
335
336void SegmentedString::advanceEmpty()
337{
338    ASSERT(!m_currentString.m_length && !isComposite());
339    m_currentChar = 0;
340}
341
342void SegmentedString::updateSlowCaseFunctionPointers()
343{
344    m_fastPathFlags = NoFastPath;
345    m_advanceFunc = &SegmentedString::advanceSlowCase;
346    m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
347}
348
349OrdinalNumber SegmentedString::currentLine() const
350{
351    return OrdinalNumber::fromZeroBasedInt(m_currentLine);
352}
353
354OrdinalNumber SegmentedString::currentColumn() const
355{
356    int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
357    return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn);
358}
359
360void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
361{
362    m_currentLine = line.zeroBasedInt();
363    m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
364}
365
366}
367