LCOV - code coverage report
Current view: directory - parser/htmlparser/src - nsScannerString.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 292 228 78.1 %
Date: 2012-06-02 Functions: 32 28 87.5 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is IBM Corporation.
      19                 :  * Portions created by IBM Corporation are Copyright (C) 2003
      20                 :  * IBM Corporation. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Darin Fisher <darin@meer.net>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include <stdlib.h>
      40                 : #include "nsScannerString.h"
      41                 : 
      42                 : 
      43                 :   /**
      44                 :    * nsScannerBufferList
      45                 :    */
      46                 : 
      47                 : #define MAX_CAPACITY ((PR_UINT32_MAX / sizeof(PRUnichar)) - \
      48                 :                       (sizeof(Buffer) + sizeof(PRUnichar)))
      49                 : 
      50                 : nsScannerBufferList::Buffer*
      51             292 : nsScannerBufferList::AllocBufferFromString( const nsAString& aString )
      52                 :   {
      53             292 :     PRUint32 len = aString.Length();
      54                 : 
      55             292 :     if (len > MAX_CAPACITY)
      56               0 :       return nsnull;
      57                 : 
      58             292 :     Buffer* buf = (Buffer*) malloc(sizeof(Buffer) + (len + 1) * sizeof(PRUnichar));
      59             292 :     if (buf)
      60                 :       {
      61                 :         // leave PRCList members of Buffer uninitialized
      62                 : 
      63             292 :         buf->mUsageCount = 0;
      64             292 :         buf->mDataEnd = buf->DataStart() + len;
      65                 : 
      66             292 :         nsAString::const_iterator source;
      67             292 :         aString.BeginReading(source);
      68             292 :         nsCharTraits<PRUnichar>::copy(buf->DataStart(), source.get(), len);
      69                 : 
      70                 :         // XXX null terminate.  this shouldn't be required, but we do it because
      71                 :         // nsScanner erroneously thinks it can dereference DataEnd :-(
      72             292 :         *buf->mDataEnd = PRUnichar(0);
      73                 :       }
      74             292 :     return buf;
      75                 :   }
      76                 : 
      77                 : nsScannerBufferList::Buffer*
      78            3491 : nsScannerBufferList::AllocBuffer( PRUint32 capacity )
      79                 :   {
      80            3491 :     if (capacity > MAX_CAPACITY)
      81               0 :       return nsnull;
      82                 : 
      83            3491 :     Buffer* buf = (Buffer*) malloc(sizeof(Buffer) + (capacity + 1) * sizeof(PRUnichar));
      84            3491 :     if (buf)
      85                 :       {
      86                 :         // leave PRCList members of Buffer uninitialized
      87                 : 
      88            3491 :         buf->mUsageCount = 0;
      89            3491 :         buf->mDataEnd = buf->DataStart() + capacity;
      90                 : 
      91                 :         // XXX null terminate.  this shouldn't be required, but we do it because
      92                 :         // nsScanner erroneously thinks it can dereference DataEnd :-(
      93            3491 :         *buf->mDataEnd = PRUnichar(0);
      94                 :       }
      95            3491 :     return buf;
      96                 :   }
      97                 : 
      98                 : void
      99            3576 : nsScannerBufferList::ReleaseAll()
     100                 :   {
     101            7166 :     while (!PR_CLIST_IS_EMPTY(&mBuffers))
     102                 :       {
     103              14 :         PRCList* node = PR_LIST_HEAD(&mBuffers);
     104              14 :         PR_REMOVE_LINK(node);
     105                 :         //printf(">>> freeing buffer @%p\n", node);
     106              14 :         free(static_cast<Buffer*>(node));
     107                 :       }
     108            3576 :   }
     109                 : 
     110                 : void
     111               0 : nsScannerBufferList::SplitBuffer( const Position& pos )
     112                 :   {
     113                 :     // splitting to the right keeps the work string and any extant token
     114                 :     // pointing to and holding a reference count on the same buffer.
     115                 : 
     116               0 :     Buffer* bufferToSplit = pos.mBuffer;
     117               0 :     NS_ASSERTION(bufferToSplit, "null pointer");
     118                 : 
     119               0 :     PRUint32 splitOffset = pos.mPosition - bufferToSplit->DataStart();
     120               0 :     NS_ASSERTION(pos.mPosition >= bufferToSplit->DataStart() &&
     121                 :                  splitOffset <= bufferToSplit->DataLength(),
     122                 :                  "split offset is outside buffer");
     123                 :     
     124               0 :     PRUint32 len = bufferToSplit->DataLength() - splitOffset;
     125               0 :     Buffer* new_buffer = AllocBuffer(len);
     126               0 :     if (new_buffer)
     127                 :       {
     128                 :         nsCharTraits<PRUnichar>::copy(new_buffer->DataStart(),
     129               0 :                                       bufferToSplit->DataStart() + splitOffset,
     130               0 :                                       len);
     131               0 :         InsertAfter(new_buffer, bufferToSplit);
     132               0 :         bufferToSplit->SetDataLength(splitOffset);
     133                 :       }
     134               0 :   }
     135                 : 
     136                 : void
     137           29025 : nsScannerBufferList::DiscardUnreferencedPrefix( Buffer* aBuf )
     138                 :   {
     139           29025 :     if (aBuf == Head())
     140                 :       {
     141           58767 :         while (!PR_CLIST_IS_EMPTY(&mBuffers) && !Head()->IsInUse())
     142                 :           {
     143            3769 :             Buffer* buffer = Head();
     144            3769 :             PR_REMOVE_LINK(buffer);
     145            3769 :             free(buffer);
     146                 :           }
     147                 :       }
     148           29025 :   }
     149                 : 
     150                 : size_t
     151           73875 : nsScannerBufferList::Position::Distance( const Position& aStart, const Position& aEnd )
     152                 :   {
     153           73875 :     size_t result = 0;
     154           73875 :     if (aStart.mBuffer == aEnd.mBuffer)
     155                 :       {
     156           73587 :         result = aEnd.mPosition - aStart.mPosition;
     157                 :       }
     158                 :     else
     159                 :       {
     160             288 :         result = aStart.mBuffer->DataEnd() - aStart.mPosition;
     161             346 :         for (Buffer* b = aStart.mBuffer->Next(); b != aEnd.mBuffer; b = b->Next())
     162              58 :           result += b->DataLength();
     163             288 :         result += aEnd.mPosition - aEnd.mBuffer->DataStart();
     164                 :       }
     165           73875 :     return result;
     166                 :   }
     167                 : 
     168                 : 
     169                 : /**
     170                 :  * nsScannerSubstring
     171                 :  */
     172                 : 
     173            4376 : nsScannerSubstring::nsScannerSubstring()
     174                 :   : mStart(nsnull, nsnull)
     175                 :   , mEnd(nsnull, nsnull)
     176                 :   , mBufferList(nsnull)
     177                 :   , mLength(0)
     178            4376 :   , mIsDirty(true)
     179                 :   {
     180            4376 :   }
     181                 : 
     182             263 : nsScannerSubstring::nsScannerSubstring( const nsAString& s )
     183                 :   : mBufferList(nsnull)
     184             263 :   , mIsDirty(true)
     185                 :   {
     186             263 :     Rebind(s);
     187             263 :   }
     188                 : 
     189            9278 : nsScannerSubstring::~nsScannerSubstring()
     190                 :   {
     191            4639 :     release_ownership_of_buffer_list();
     192            4639 :   }
     193                 : 
     194                 : PRInt32
     195              25 : nsScannerSubstring::CountChar( PRUnichar c ) const
     196                 :   {
     197                 :       /*
     198                 :         re-write this to use a counting sink
     199                 :        */
     200                 : 
     201              25 :     size_type result = 0;
     202              25 :     size_type lengthToExamine = Length();
     203                 : 
     204              25 :     nsScannerIterator iter;
     205              25 :     for ( BeginReading(iter); ; )
     206                 :       {
     207              25 :         PRInt32 lengthToExamineInThisFragment = iter.size_forward();
     208              25 :         const PRUnichar* fromBegin = iter.get();
     209              25 :         result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
     210              25 :         if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
     211              25 :           return result;
     212               0 :         iter.advance(lengthToExamineInThisFragment);
     213                 :       }
     214                 :       // never reached; quiets warnings
     215                 :     return 0;
     216                 :   }
     217                 : 
     218                 : void
     219            1063 : nsScannerSubstring::Rebind( const nsScannerSubstring& aString,
     220                 :                             const nsScannerIterator& aStart, 
     221                 :                             const nsScannerIterator& aEnd )
     222                 :   {
     223                 :     // allow for the case where &aString == this
     224                 : 
     225            1063 :     aString.acquire_ownership_of_buffer_list();
     226            1063 :     release_ownership_of_buffer_list();
     227                 : 
     228            1063 :     mStart      = aStart;
     229            1063 :     mEnd        = aEnd;
     230            1063 :     mBufferList = aString.mBufferList;
     231            1063 :     mLength     = Distance(aStart, aEnd);
     232            1063 :     mIsDirty    = true;
     233            1063 :   }
     234                 : 
     235                 : void
     236             288 : nsScannerSubstring::Rebind( const nsAString& aString )
     237                 :   {
     238             288 :     release_ownership_of_buffer_list();
     239                 : 
     240             576 :     mBufferList = new nsScannerBufferList(AllocBufferFromString(aString));
     241             288 :     mIsDirty    = true;
     242                 : 
     243             288 :     init_range_from_buffer_list();
     244             288 :     acquire_ownership_of_buffer_list();
     245             288 :   }
     246                 : 
     247                 : const nsSubstring&
     248            2105 : nsScannerSubstring::AsString() const
     249                 :   {
     250            2105 :     if (mIsDirty)
     251                 :       {
     252            1038 :         nsScannerSubstring* mutable_this = const_cast<nsScannerSubstring*>(this);
     253                 : 
     254            1038 :         if (mStart.mBuffer == mEnd.mBuffer) {
     255                 :           // We only have a single fragment to deal with, so just return it
     256                 :           // as a substring.
     257            1038 :           mutable_this->mFlattenedRep.Rebind(mStart.mPosition, mEnd.mPosition);
     258                 :         } else {
     259                 :           // Otherwise, we need to copy the data into a flattened buffer.
     260               0 :           nsScannerIterator start, end;
     261               0 :           CopyUnicodeTo(BeginReading(start), EndReading(end), mutable_this->mFlattenedRep);
     262                 :         }
     263                 : 
     264            1038 :         mutable_this->mIsDirty = false;
     265                 :       }
     266                 : 
     267            2105 :     return mFlattenedRep;
     268                 :   }
     269                 : 
     270                 : nsScannerIterator&
     271           34642 : nsScannerSubstring::BeginReading( nsScannerIterator& iter ) const
     272                 :   {
     273           34642 :     iter.mOwner = this;
     274                 : 
     275           34642 :     iter.mFragment.mBuffer = mStart.mBuffer;
     276           34642 :     iter.mFragment.mFragmentStart = mStart.mPosition;
     277           34642 :     if (mStart.mBuffer == mEnd.mBuffer)
     278           32381 :       iter.mFragment.mFragmentEnd = mEnd.mPosition;
     279                 :     else
     280            2261 :       iter.mFragment.mFragmentEnd = mStart.mBuffer->DataEnd();
     281                 : 
     282           34642 :     iter.mPosition = mStart.mPosition;
     283           34642 :     iter.normalize_forward();
     284           34642 :     return iter;
     285                 :   }
     286                 : 
     287                 : nsScannerIterator&
     288            3495 : nsScannerSubstring::EndReading( nsScannerIterator& iter ) const
     289                 :   {
     290            3495 :     iter.mOwner = this;
     291                 : 
     292            3495 :     iter.mFragment.mBuffer = mEnd.mBuffer;
     293            3495 :     iter.mFragment.mFragmentEnd = mEnd.mPosition;
     294            3495 :     if (mStart.mBuffer == mEnd.mBuffer)
     295            3288 :       iter.mFragment.mFragmentStart = mStart.mPosition;
     296                 :     else
     297             207 :       iter.mFragment.mFragmentStart = mEnd.mBuffer->DataStart();
     298                 : 
     299            3495 :     iter.mPosition = mEnd.mPosition;
     300                 :     // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )|
     301            3495 :     return iter;
     302                 :   }
     303                 : 
     304                 : bool
     305           30267 : nsScannerSubstring::GetNextFragment( nsScannerFragment& frag ) const
     306                 :   {
     307                 :     // check to see if we are at the end of the buffer list
     308           30267 :     if (frag.mBuffer == mEnd.mBuffer)
     309           29838 :       return false;
     310                 : 
     311             429 :     frag.mBuffer = static_cast<const Buffer*>(PR_NEXT_LINK(frag.mBuffer));
     312                 : 
     313             429 :     if (frag.mBuffer == mStart.mBuffer)
     314               0 :       frag.mFragmentStart = mStart.mPosition;
     315                 :     else
     316             429 :       frag.mFragmentStart = frag.mBuffer->DataStart();
     317                 : 
     318             429 :     if (frag.mBuffer == mEnd.mBuffer)
     319             359 :       frag.mFragmentEnd = mEnd.mPosition;
     320                 :     else
     321              70 :       frag.mFragmentEnd = frag.mBuffer->DataEnd();
     322                 : 
     323             429 :     return true;
     324                 :   }
     325                 : 
     326                 : bool
     327              14 : nsScannerSubstring::GetPrevFragment( nsScannerFragment& frag ) const
     328                 :   {
     329                 :     // check to see if we are at the beginning of the buffer list
     330              14 :     if (frag.mBuffer == mStart.mBuffer)
     331               0 :       return false;
     332                 : 
     333              14 :     frag.mBuffer = static_cast<const Buffer*>(PR_PREV_LINK(frag.mBuffer));
     334                 : 
     335              14 :     if (frag.mBuffer == mStart.mBuffer)
     336               2 :       frag.mFragmentStart = mStart.mPosition;
     337                 :     else
     338              12 :       frag.mFragmentStart = frag.mBuffer->DataStart();
     339                 : 
     340              14 :     if (frag.mBuffer == mEnd.mBuffer)
     341               0 :       frag.mFragmentEnd = mEnd.mPosition;
     342                 :     else
     343              14 :       frag.mFragmentEnd = frag.mBuffer->DataEnd();
     344                 : 
     345              14 :     return true;
     346                 :   }
     347                 : 
     348                 : 
     349                 :   /**
     350                 :    * nsScannerString
     351                 :    */
     352                 : 
     353            3288 : nsScannerString::nsScannerString( Buffer* aBuf )
     354                 :   {
     355            3288 :     mBufferList = new nsScannerBufferList(aBuf);
     356                 : 
     357            3288 :     init_range_from_buffer_list();
     358            3288 :     acquire_ownership_of_buffer_list();
     359            3288 :   }
     360                 : 
     361                 : void
     362             207 : nsScannerString::AppendBuffer( Buffer* aBuf )
     363                 :   {
     364             207 :     mBufferList->Append(aBuf);
     365             207 :     mLength += aBuf->DataLength();
     366                 : 
     367             207 :     mEnd.mBuffer = aBuf;
     368             207 :     mEnd.mPosition = aBuf->DataEnd();
     369                 : 
     370             207 :     mIsDirty = true;
     371             207 :   }
     372                 : 
     373                 : void
     374           22227 : nsScannerString::DiscardPrefix( const nsScannerIterator& aIter )
     375                 :   {
     376           22227 :     Position old_start(mStart);
     377           22227 :     mStart = aIter;
     378           22227 :     mLength -= Position::Distance(old_start, mStart);
     379                 :     
     380           22227 :     mStart.mBuffer->IncrementUsageCount();
     381           22227 :     old_start.mBuffer->DecrementUsageCount();
     382                 : 
     383           22227 :     mBufferList->DiscardUnreferencedPrefix(old_start.mBuffer);
     384                 : 
     385           22227 :     mIsDirty = true;
     386           22227 :   }
     387                 : 
     388                 : void
     389               0 : nsScannerString::UngetReadable( const nsAString& aReadable, const nsScannerIterator& aInsertPoint )
     390                 :     /*
     391                 :      * Warning: this routine manipulates the shared buffer list in an unexpected way.
     392                 :      *  The original design did not really allow for insertions, but this call promises
     393                 :      *  that if called for a point after the end of all extant token strings, that no token string
     394                 :      *  or the work string will be invalidated.
     395                 :      *
     396                 :      *  This routine is protected because it is the responsibility of the derived class to keep those promises.
     397                 :      */
     398                 :   {
     399               0 :     Position insertPos(aInsertPoint);
     400                 : 
     401               0 :     mBufferList->SplitBuffer(insertPos);
     402                 :       // splitting to the right keeps the work string and any extant token pointing to and
     403                 :       //  holding a reference count on the same buffer
     404                 : 
     405               0 :     Buffer* new_buffer = AllocBufferFromString(aReadable);
     406                 :       // make a new buffer with all the data to insert...
     407                 :       //  BULLSHIT ALERT: we may have empty space to re-use in the split buffer, measure the cost
     408                 :       //  of this and decide if we should do the work to fill it
     409                 : 
     410               0 :     Buffer* buffer_to_split = insertPos.mBuffer;
     411               0 :     mBufferList->InsertAfter(new_buffer, buffer_to_split);
     412               0 :     mLength += aReadable.Length();
     413                 : 
     414               0 :     mEnd.mBuffer = mBufferList->Tail();
     415               0 :     mEnd.mPosition = mEnd.mBuffer->DataEnd();
     416                 : 
     417               0 :     mIsDirty = true;
     418               0 :   }
     419                 : 
     420                 : void
     421               0 : nsScannerString::ReplaceCharacter(nsScannerIterator& aPosition, PRUnichar aChar)
     422                 :   {
     423                 :     // XXX Casting a const to non-const. Unless the base class
     424                 :     // provides support for writing iterators, this is the best
     425                 :     // that can be done.
     426               0 :     PRUnichar* pos = const_cast<PRUnichar*>(aPosition.get());
     427               0 :     *pos = aChar;
     428                 : 
     429               0 :     mIsDirty = true;
     430               0 :   }
     431                 : 
     432                 : 
     433                 :   /**
     434                 :    * nsScannerSharedSubstring
     435                 :    */
     436                 : 
     437                 : void
     438            2176 : nsScannerSharedSubstring::Rebind(const nsScannerIterator &aStart,
     439                 :                               const nsScannerIterator &aEnd)
     440                 : {
     441                 :   // If the start and end positions are inside the same buffer, we must
     442                 :   // acquire ownership of the buffer.  If not, we can optimize by not holding
     443                 :   // onto it.
     444                 : 
     445            2176 :   Buffer *buffer = const_cast<Buffer*>(aStart.buffer());
     446            2176 :   bool sameBuffer = buffer == aEnd.buffer();
     447                 : 
     448                 :   nsScannerBufferList *bufferList;
     449                 : 
     450            2176 :   if (sameBuffer) {
     451            2159 :     bufferList = aStart.mOwner->mBufferList;
     452            2159 :     bufferList->AddRef();
     453            2159 :     buffer->IncrementUsageCount();
     454                 :   }
     455                 : 
     456            2176 :   if (mBufferList)
     457               0 :     ReleaseBuffer();
     458                 : 
     459            2176 :   if (sameBuffer) {
     460            2159 :     mBuffer = buffer;
     461            2159 :     mBufferList = bufferList;
     462            2159 :     mString.Rebind(aStart.mPosition, aEnd.mPosition);
     463                 :   } else {
     464              17 :     mBuffer = nsnull;
     465              17 :     mBufferList = nsnull;
     466              17 :     CopyUnicodeTo(aStart, aEnd, mString);
     467                 :   }
     468            2176 : }
     469                 : 
     470                 : void
     471            2159 : nsScannerSharedSubstring::ReleaseBuffer()
     472                 : {
     473            2159 :   NS_ASSERTION(mBufferList, "Should only be called with non-null mBufferList");
     474            2159 :   mBuffer->DecrementUsageCount();
     475            2159 :   mBufferList->DiscardUnreferencedPrefix(mBuffer);
     476            2159 :   mBufferList->Release();
     477            2159 : }
     478                 : 
     479                 : void
     480              11 : nsScannerSharedSubstring::MakeMutable()
     481                 : {
     482              22 :   nsString temp(mString); // this will force a copy of the data
     483              11 :   mString.Assign(temp);   // mString will now share the just-allocated buffer
     484                 : 
     485              11 :   ReleaseBuffer();
     486                 : 
     487              11 :   mBuffer = nsnull;
     488              11 :   mBufferList = nsnull;
     489              11 : }
     490                 : 
     491                 :   /**
     492                 :    * utils -- based on code from nsReadableUtils.cpp
     493                 :    */
     494                 : 
     495                 : // private helper function
     496                 : static inline
     497                 : nsAString::iterator&
     498            6827 : copy_multifragment_string( nsScannerIterator& first, const nsScannerIterator& last, nsAString::iterator& result )
     499                 :   {
     500                 :     typedef nsCharSourceTraits<nsScannerIterator> source_traits;
     501                 :     typedef nsCharSinkTraits<nsAString::iterator> sink_traits;
     502                 : 
     503           17672 :     while ( first != last )
     504                 :       {
     505            4018 :         PRUint32 distance = source_traits::readable_distance(first, last);
     506            4018 :         sink_traits::write(result, source_traits::read(first), distance);
     507            4018 :         NS_ASSERTION(distance > 0, "|copy_multifragment_string| will never terminate");
     508            4018 :         source_traits::advance(first, distance);
     509                 :       }
     510                 : 
     511            6827 :     return result;
     512                 :   }
     513                 : 
     514                 : void
     515            6803 : CopyUnicodeTo( const nsScannerIterator& aSrcStart,
     516                 :                const nsScannerIterator& aSrcEnd,
     517                 :                nsAString& aDest )
     518                 :   {
     519            6803 :     nsAString::iterator writer;
     520            6803 :     if (!EnsureStringLength(aDest, Distance(aSrcStart, aSrcEnd))) {
     521               0 :       aDest.Truncate();
     522               0 :       return; // out of memory
     523                 :     }
     524            6803 :     aDest.BeginWriting(writer);
     525            6803 :     nsScannerIterator fromBegin(aSrcStart);
     526                 :     
     527            6803 :     copy_multifragment_string(fromBegin, aSrcEnd, writer);
     528                 :   }
     529                 : 
     530                 : void
     531            2187 : AppendUnicodeTo( const nsScannerIterator& aSrcStart,
     532                 :                  const nsScannerIterator& aSrcEnd,
     533                 :                  nsScannerSharedSubstring& aDest )
     534                 :   {
     535                 :     // Check whether we can just create a dependent string.
     536            2187 :     if (aDest.str().IsEmpty()) {
     537                 :       // We can just make |aDest| point to the buffer.
     538                 :       // This will take care of copying if the buffer spans fragments.
     539            2176 :       aDest.Rebind(aSrcStart, aSrcEnd);
     540                 :     } else {
     541                 :       // The dest string is not empty, so it can't be a dependent substring.
     542              11 :       AppendUnicodeTo(aSrcStart, aSrcEnd, aDest.writable());
     543                 :     }
     544            2187 :   }
     545                 : 
     546                 : void
     547              24 : AppendUnicodeTo( const nsScannerIterator& aSrcStart,
     548                 :                  const nsScannerIterator& aSrcEnd,
     549                 :                  nsAString& aDest )
     550                 :   {
     551              24 :     nsAString::iterator writer;
     552              24 :     PRUint32 oldLength = aDest.Length();
     553              24 :     if (!EnsureStringLength(aDest, oldLength + Distance(aSrcStart, aSrcEnd)))
     554               0 :       return; // out of memory
     555              24 :     aDest.BeginWriting(writer).advance(oldLength);
     556              24 :     nsScannerIterator fromBegin(aSrcStart);
     557                 :     
     558              24 :     copy_multifragment_string(fromBegin, aSrcEnd, writer);
     559                 :   }
     560                 : 
     561                 : bool
     562              25 : FindCharInReadable( PRUnichar aChar,
     563                 :                     nsScannerIterator& aSearchStart,
     564                 :                     const nsScannerIterator& aSearchEnd )
     565                 :   {
     566              50 :     while ( aSearchStart != aSearchEnd )
     567                 :       {
     568                 :         PRInt32 fragmentLength;
     569              25 :         if ( SameFragment(aSearchStart, aSearchEnd) ) 
     570               0 :           fragmentLength = aSearchEnd.get() - aSearchStart.get();
     571                 :         else
     572              25 :           fragmentLength = aSearchStart.size_forward();
     573                 : 
     574              25 :         const PRUnichar* charFoundAt = nsCharTraits<PRUnichar>::find(aSearchStart.get(), fragmentLength, aChar);
     575              25 :         if ( charFoundAt ) {
     576              25 :           aSearchStart.advance( charFoundAt - aSearchStart.get() );
     577              25 :           return true;
     578                 :         }
     579                 : 
     580               0 :         aSearchStart.advance(fragmentLength);
     581                 :       }
     582                 : 
     583               0 :     return false;
     584                 :   }
     585                 : 
     586                 : bool
     587              25 : FindInReadable( const nsAString& aPattern,
     588                 :                 nsScannerIterator& aSearchStart,
     589                 :                 nsScannerIterator& aSearchEnd,
     590                 :                 const nsStringComparator& compare )
     591                 :   {
     592              25 :     bool found_it = false;
     593                 : 
     594                 :       // only bother searching at all if we're given a non-empty range to search
     595              25 :     if ( aSearchStart != aSearchEnd )
     596                 :       {
     597              25 :         nsAString::const_iterator aPatternStart, aPatternEnd;
     598              25 :         aPattern.BeginReading(aPatternStart);
     599              25 :         aPattern.EndReading(aPatternEnd);
     600                 : 
     601                 :           // outer loop keeps searching till we find it or run out of string to search
     602              25 :         while ( !found_it )
     603                 :           {
     604                 :               // fast inner loop (that's what it's called, not what it is) looks for a potential match
     605              75 :             while ( aSearchStart != aSearchEnd &&
     606              25 :                     compare(aPatternStart.get(), aSearchStart.get(), 1, 1) )
     607               0 :               ++aSearchStart;
     608                 : 
     609                 :               // if we broke out of the `fast' loop because we're out of string ... we're done: no match
     610              25 :             if ( aSearchStart == aSearchEnd )
     611               0 :               break;
     612                 : 
     613                 :               // otherwise, we're at a potential match, let's see if we really hit one
     614              25 :             nsAString::const_iterator testPattern(aPatternStart);
     615              25 :             nsScannerIterator testSearch(aSearchStart);
     616                 : 
     617                 :               // slow inner loop verifies the potential match (found by the `fast' loop) at the current position
     618             150 :             for(;;)
     619                 :               {
     620                 :                   // we already compared the first character in the outer loop,
     621                 :                   //  so we'll advance before the next comparison
     622             175 :                 ++testPattern;
     623             175 :                 ++testSearch;
     624                 : 
     625                 :                   // if we verified all the way to the end of the pattern, then we found it!
     626             175 :                 if ( testPattern == aPatternEnd )
     627                 :                   {
     628              25 :                     found_it = true;
     629              25 :                     aSearchEnd = testSearch; // return the exact found range through the parameters
     630              25 :                     break;
     631                 :                   }
     632                 : 
     633                 :                   // if we got to end of the string we're searching before we hit the end of the
     634                 :                   //  pattern, we'll never find what we're looking for
     635             150 :                 if ( testSearch == aSearchEnd )
     636                 :                   {
     637               0 :                     aSearchStart = aSearchEnd;
     638               0 :                     break;
     639                 :                   }
     640                 : 
     641                 :                   // else if we mismatched ... it's time to advance to the next search position
     642                 :                   //  and get back into the `fast' loop
     643             150 :                 if ( compare(testPattern.get(), testSearch.get(), 1, 1) )
     644                 :                   {
     645               0 :                     ++aSearchStart;
     646               0 :                     break;
     647                 :                   }
     648                 :               }
     649                 :           }
     650                 :       }
     651                 : 
     652              25 :     return found_it;
     653                 :   }
     654                 : 
     655                 :   /**
     656                 :    * This implementation is simple, but does too much work.
     657                 :    * It searches the entire string from left to right, and returns the last match found, if any.
     658                 :    * This implementation will be replaced when I get |reverse_iterator|s working.
     659                 :    */
     660                 : bool
     661               0 : RFindInReadable( const nsAString& aPattern,
     662                 :                  nsScannerIterator& aSearchStart,
     663                 :                  nsScannerIterator& aSearchEnd,
     664                 :                  const nsStringComparator& aComparator )
     665                 :   {
     666               0 :     bool found_it = false;
     667                 : 
     668               0 :     nsScannerIterator savedSearchEnd(aSearchEnd);
     669               0 :     nsScannerIterator searchStart(aSearchStart), searchEnd(aSearchEnd);
     670                 : 
     671               0 :     while ( searchStart != searchEnd )
     672                 :       {
     673               0 :         if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) )
     674                 :           {
     675               0 :             found_it = true;
     676                 : 
     677                 :               // this is the best match so far, so remember it
     678               0 :             aSearchStart = searchStart;
     679               0 :             aSearchEnd = searchEnd;
     680                 : 
     681                 :               // ...and get ready to search some more
     682                 :               //  (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns)
     683               0 :             ++searchStart;
     684               0 :             searchEnd = savedSearchEnd;
     685                 :           }
     686                 :       }
     687                 : 
     688                 :       // if we never found it, return an empty range
     689               0 :     if ( !found_it )
     690               0 :       aSearchStart = aSearchEnd;
     691                 : 
     692               0 :     return found_it;
     693                 :   }

Generated by: LCOV version 1.7