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 "core/platform/text/SegmentedString.h" 22 23 namespace WebCore { 24 25 SegmentedString::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 47 const 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 73 unsigned 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 90 void 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 101 void 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 118 void 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 133 void 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 159 void SegmentedString::close() 160 { 161 // Closing a stream twice is likely a coding mistake. 162 ASSERT(!m_closed); 163 m_closed = true; 164 } 165 166 void 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 180 void 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 194 void 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 213 String 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 231 void 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 240 void SegmentedString::advance8() 241 { 242 ASSERT(!m_pushedChar1); 243 decrementAndCheckLength(); 244 m_currentChar = m_currentString.incrementAndGetCurrentChar8(); 245 } 246 247 void SegmentedString::advance16() 248 { 249 ASSERT(!m_pushedChar1); 250 decrementAndCheckLength(); 251 m_currentChar = m_currentString.incrementAndGetCurrentChar16(); 252 } 253 254 void 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 266 void 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 278 void 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 303 void 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 336 void SegmentedString::advanceEmpty() 337 { 338 ASSERT(!m_currentString.m_length && !isComposite()); 339 m_currentChar = 0; 340 } 341 342 void SegmentedString::updateSlowCaseFunctionPointers() 343 { 344 m_fastPathFlags = NoFastPath; 345 m_advanceFunc = &SegmentedString::advanceSlowCase; 346 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase; 347 } 348 349 OrdinalNumber SegmentedString::currentLine() const 350 { 351 return OrdinalNumber::fromZeroBasedInt(m_currentLine); 352 } 353 354 OrdinalNumber SegmentedString::currentColumn() const 355 { 356 int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine; 357 return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn); 358 } 359 360 void 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