StringData.cxx
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:18k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /* ====================================================================
  2.  * The Vovida Software License, Version 1.0 
  3.  * 
  4.  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
  5.  * 
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in
  15.  *    the documentation and/or other materials provided with the
  16.  *    distribution.
  17.  * 
  18.  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  19.  *    and "Vovida Open Communication Application Library (VOCAL)" must
  20.  *    not be used to endorse or promote products derived from this
  21.  *    software without prior written permission. For written
  22.  *    permission, please contact vocal@vovida.org.
  23.  *
  24.  * 4. Products derived from this software may not be called "VOCAL", nor
  25.  *    may "VOCAL" appear in their name, without prior written
  26.  *    permission of Vovida Networks, Inc.
  27.  * 
  28.  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  29.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
  31.  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
  32.  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
  33.  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
  34.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  36.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  37.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  39.  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  40.  * DAMAGE.
  41.  * 
  42.  * ====================================================================
  43.  * 
  44.  * This software consists of voluntary contributions made by Vovida
  45.  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  46.  * Inc.  For more information on Vovida Networks, Inc., please see
  47.  * <http://www.vovida.org/>.
  48.  *
  49.  */
  50. static const char* const StringData_cxx_Version =
  51.     "$Id: StringData.cxx,v 1.67 2001/06/29 03:56:00 bko Exp $";
  52. //Authors: Sunitha Kumar, Cullen Jennings
  53. #include <cstdio>
  54. #include <ctype.h>
  55. #include "cpLog.h"
  56. #include "StringData.hxx"
  57. #include "DataException.hxx"
  58. #if USE_HASH_MAP
  59. #include <hash_map>
  60. #endif
  61. #include <cctype>
  62. #define INLINE_ inline
  63. static INLINE_ 
  64. bool isIn(char c, const char* match)
  65. {
  66.     char p;
  67.     while((p = *match++))
  68.     {
  69. if(p == c)
  70. {
  71.     return true;
  72. }
  73.     }
  74.     return false;
  75. }
  76. StringData::StringData():
  77.         hash_val(0),
  78.         hash_valid(false)
  79. {}
  80. StringData::StringData( const char* str, int length ):
  81.         hash_val(0),
  82.         hash_valid(false),
  83.         buf(str, length)
  84. {
  85.     buf = str;
  86. }
  87. StringData::StringData( const char* str ):
  88.         hash_val(0),
  89.         hash_valid(false)
  90. {
  91.     buf = str;
  92. }
  93. StringData::StringData( const string& str):
  94.         hash_val(0),
  95.         hash_valid(false)
  96. {
  97.     buf = str;
  98. }
  99. StringData::StringData( const mstring& mstr):
  100.         hash_val(0),
  101.         hash_valid(false)
  102. {
  103.     buf = mstr;
  104. }
  105. StringData::StringData( int value):
  106.         hash_val(0),
  107.         hash_valid(false)
  108. {
  109.     char str[256];
  110.     sprintf(str, "%d", value);
  111.     buf = str;
  112. }
  113. StringData::StringData( const StringData& data )
  114. {
  115.     buf = data.buf;
  116.     hash_val = (data.hash_val);
  117.     hash_valid = (data.hash_valid);
  118. }
  119. StringData&
  120. StringData::operator=( const char* str )
  121. {
  122.     buf = str;
  123.     hash_valid = false;
  124.     return (*this);
  125. }
  126. StringData&
  127. StringData::operator=( const StringData& data )
  128. {
  129.     if (this != &data)
  130.     {
  131.         buf = data.buf;
  132.         hash_valid = false;
  133.     }
  134.     return (*this);
  135. }
  136. const char*
  137. StringData::getData() const
  138. {
  139.     return buf.c_str();
  140. }
  141. const char*
  142. StringData::getDataBuf() const
  143. {
  144.     return buf.c_str();
  145. }
  146. #if 0
  147. void StringData::substr( int start, int length, char* deststr ) const
  148. {
  149.     if ( ( start < 0 ) || (length < 1) )
  150.     {
  151.         cpLog(LOG_ERR, "StringData: substr: incorrect start or length parameters");
  152.         throw DataAccessError(OUT_OF_RANGE);
  153.     }
  154.     else
  155.     {
  156.         char* str = buffer->getBuffer();
  157.         for ( *deststr = *str; *str != ''; deststr++, str++, *deststr = *str );
  158.         //assign the null char.
  159.         *deststr = '';
  160.     }
  161. }
  162. #endif
  163. char
  164. StringData::getChar(int i) const
  165. {
  166.     if (( i < 0 ) || (i > static_cast < int > (buf.size()) ) )
  167.     {
  168.         cpLog(LOG_ERR, "StringData:getchar: i is out of range.");
  169.         throw DataException(
  170.             "i is out of range",
  171.             __FILE__,
  172.             __LINE__
  173.         );
  174.         return '';
  175.     }
  176.     return buf[i];
  177. }
  178. void StringData::setchar(int i, char c)
  179. {
  180.     hash_valid = false;
  181.     if (( i < 0) || (i > static_cast < int > (buf.size()) ) )
  182.     {
  183.         cpLog(LOG_ERR, "StringData:setchar: i is out of range.");
  184.         throw DataException(
  185.             "i is out of range",
  186.             __FILE__,
  187.             __LINE__
  188.         );
  189.     }
  190.     else
  191.     {
  192.         buf[i] = c;
  193.     }
  194. }
  195. char
  196. StringData::operator[](int i)
  197. {
  198.     char ch;
  199.     ch = getChar(i);
  200.     return ch;
  201. }
  202. int
  203. StringData::length() const
  204. {
  205.     return buf.size();
  206. }
  207. bool StringData::operator==(const char* str) const
  208. {
  209.     return ( buf == str );
  210. }
  211. bool StringData::operator==( const StringData& data) const
  212. {
  213. #if 1 
  214.     return ( buf == data.buf );
  215. #else
  216.     if (data.hashfn() == hashfn())
  217.     {
  218.         return ( buf == data.buf );
  219.     }
  220.     else
  221.     {
  222.         return false;
  223.     }
  224. #endif
  225. }
  226. bool StringData::operator!=(const char* str) const
  227. {
  228.     return ( buf != str);
  229. }
  230. bool StringData::operator!=(const StringData& data) const
  231. {
  232.     return ( buf != data.buf );
  233. #if 0
  234.     if (data.hashfn() == hashfn())
  235.     {
  236.         return ( buf != data.buf );
  237.     }
  238.     else
  239.     {
  240.         return true;
  241.     }
  242. #endif
  243. }
  244. bool
  245. StringData::operator>(const StringData& data) const
  246. {
  247.     return ( buf > data.buf );
  248. }
  249. bool
  250. StringData::operator<(const StringData& data) const
  251. {
  252.     return ( buf < data.buf );
  253. }
  254. StringData
  255. StringData::operator+(const StringData& data) const
  256. {
  257.     return ( buf + data.buf );
  258. }
  259. StringData
  260. StringData::operator+(const char* str) const
  261. {
  262.     return ( buf + str );
  263. }
  264. void
  265. StringData::operator+=(const StringData& data)
  266. {
  267.     hash_valid = false;
  268.     buf += data.buf;
  269. }
  270. void
  271. StringData::operator+=(const char* str)
  272. {
  273.     hash_valid = false;
  274.     buf += str;
  275. }
  276. StringData::~StringData()
  277. {}
  278. void
  279. StringData::erase()
  280. {
  281.     buf.erase();
  282.     hash_valid = false;
  283. }
  284. StringData::operator string() const
  285. {
  286.     return buf;
  287. }
  288. StringData::operator const char*() const
  289. {
  290.     return buf.c_str();
  291. }
  292. StringData::operator mstring() const
  293. {
  294.     return mstring(buf);
  295. }
  296. StringData::operator int() const
  297. {
  298.     size_t l = buf.length();
  299.     int val = 0;
  300.     size_t p = 0;
  301.     while (l--)
  302.     {
  303.         char c = buf[p++];
  304.         if ((c >= '0') && (c <= '9'))
  305.         {
  306.             val *= 10;
  307.             val += c - '0';
  308.         }
  309.         else
  310.         {
  311.             return val;
  312.         }
  313.     }
  314.     return val;
  315. }
  316. #if USE_HASH_MAP
  317. size_t
  318. StringData::hashfn() const
  319. {
  320.     hash < const char* > x;
  321.     return x(getData());
  322.     if (!hash_valid)
  323.     {
  324.         hash < const char* > x;
  325.         hash_val = x(buf.c_str());
  326.         hash_valid = true;
  327.     }
  328.     return hash_val;
  329. }
  330. #endif
  331. // size_t
  332. // Data::hashfn() const
  333. // {
  334. //     assert (hash_valid == true);
  335. //     return hash_val;
  336. // }
  337. int StringData::find( const StringData& match, int start)
  338. {
  339.     return static_cast < int > (buf.find(match.buf,
  340.                                          static_cast < string::size_type > (start)));
  341. }
  342. int StringData::match( StringData match, StringData* retModifiedData, bool replace, StringData replaceWith)
  343. {
  344. #if 1
  345.     int retVal;
  346.     string::size_type pos = buf.find(match.getData());
  347.     if (pos == string::npos)
  348.     {
  349.         cpLog(LOG_DEBUG_STACK, "Match not found");
  350.         return NOT_FOUND;
  351.     }
  352.     string::size_type replacePos = pos + match.length();
  353.     retVal = FIRST;
  354.     if (retModifiedData)
  355.     {
  356.         (*retModifiedData) = buf.substr(0, pos);
  357.         if (retModifiedData->length()) retVal = FOUND;
  358.     }
  359.     if (replace)
  360.     {
  361.         if (replacePos <= buf.size() )
  362.         {
  363.             hash_valid = false;
  364.             buf.replace(0, replacePos, replaceWith.getData());
  365.         }
  366.         else
  367.         {
  368.             printf("buf =<%s> match =<%s>n", buf.c_str() , match.getData() );
  369.             printf("pos=%d  match.len=%d replacePos=%d  buf.size()= %dn",
  370.                    pos,
  371.                    match.length(),
  372.                    replacePos,
  373.                    buf.size() );
  374.         }
  375.     }
  376.     return retVal;
  377. #else
  378.     int pos = static_cast < int > (buf.find(match.getData()));
  379.     if (pos == static_cast < int > (string::npos))
  380.     {
  381.         cpLog(LOG_DEBUG_STACK, "Match not found");
  382.         pos = NOT_FOUND;
  383.     }
  384.     else
  385.     {
  386.         if (data)
  387.         {
  388.             (*data) = buf.substr(0, pos);
  389.         }
  390.         if (replace)
  391.         {
  392.             hash_valid = false;
  393.             buf.replace(0, (pos + match.length()), replaceWith.getData());
  394.         }
  395.         else
  396.         {
  397.         }
  398.         if ( (data->length() == 0) && (pos != ( (int) string::npos) ) )
  399.         {
  400.             //the match string is the first item.
  401.             pos = -2;
  402.             pos = FIRST;
  403.         }
  404.     }
  405.     if ( (pos != NOT_FOUND) && (pos != FIRST) )
  406.     {
  407.         pos = FOUND;
  408.     }
  409.     return pos;
  410. #endif
  411. }
  412. /*
  413.  
  414. int  Data::match( const Data& match, Data* retModifiedData, bool replace, const Data& replaceWith)
  415. {
  416.     int retVal;
  417.     string::size_type pos = buf.find(match.getData());
  418.     
  419.     if (pos == string::npos)
  420.     {
  421.         cpLog(LOG_DEBUG_STACK, "Match not found");
  422.         return NOT_FOUND;
  423.     }
  424.  
  425.     string::size_type replacePos = pos + match.length();
  426.     retVal = FIRST;
  427.  
  428.     if (retModifiedData)
  429.     {
  430.         (*retModifiedData) = buf.substr(0, pos);
  431. if(retModifiedData->length()) retVal = FOUND;
  432.     }
  433.  
  434.     if (replace)
  435.     {
  436.         buf.replace(0, replacePos, replaceWith.getData());
  437.     }
  438.  
  439.     return retVal;
  440. }
  441.  
  442. */
  443. bool isEqualNoCase(const StringData& left, const StringData& right )
  444. {
  445.     string::const_iterator leftIter = left.buf.begin();
  446.     string::const_iterator rightIter = right.buf.begin();
  447.     while ( (leftIter != left.buf.end()) && (rightIter != right.buf.end()) )
  448.     {
  449.         if (toupper(*leftIter) != toupper(*rightIter))
  450.         {
  451.             return false;
  452.         }
  453.         ++leftIter;
  454.         ++rightIter;
  455.     }
  456.     if ( (leftIter != left.buf.end()) || (rightIter != right.buf.end()) )
  457.     {
  458.         // since both aren't the same length, they're not equal
  459.         return false;
  460.     }
  461.     return true;
  462. }
  463. void StringData::removeSpaces()
  464. {
  465.     hash_valid = false;
  466.     //removes spaces before and after the characters.
  467.     //Leaves the embedded spaces as is.
  468.     /*
  469.      Data beforeSpace="";
  470.      Data afterSpace="";
  471.      int found;
  472.     do
  473. {
  474.         beforeSpace="";
  475.         found = data->match(SPACE, &beforeSpace, false);
  476.         if (found == FIRST)
  477.         {
  478.             //replace with nothing
  479.             data->match(SPACE, &beforeSpace, true);
  480.         }
  481. }while (found == FIRST);
  482.     */
  483.     if (buf.length() == 0)
  484.     {
  485.         return ;
  486.     }
  487.     string::size_type beforeval;
  488.     do
  489.     {
  490.         beforeval = buf.find(SPACE);
  491.         if (beforeval != 0)
  492.         {
  493.             break;
  494.         }
  495.         buf.replace(beforeval, strlen(SPACE) , "");
  496.     }
  497.     while (beforeval == 0);
  498.     string::size_type afterval;
  499.     do
  500.     {
  501.         //afterSpace="";
  502.         //proceed to the last character in Data.
  503.         // string tempstring = buf;
  504.         afterval = buf.rfind(SPACE);
  505.         //if there are chars after val, discard .
  506.         if (afterval + 1 < buf.length())
  507.         {
  508.             break;
  509.         }
  510.         buf.replace(afterval, strlen(SPACE) , "");
  511.         //Data tempdata(tempstring);
  512.         //*data = tempdata;
  513.     }
  514.     while (afterval != string::npos);
  515. }
  516. void
  517. StringData::expand(StringData startFrom, StringData findstr, StringData replstr, StringData delimiter)
  518. {
  519.     hash_valid = false;
  520.     string::size_type startPos = buf.find(startFrom.getData());
  521.     if (startPos < string::npos)
  522.     {
  523.         string::size_type delimPos = buf.find(delimiter.getData(), startPos);
  524.         string::size_type findPos = buf.find( findstr.getData(), startPos);
  525.         while (findPos < delimPos)
  526.         {
  527.             //found replstr, replace
  528.             buf.replace( findPos, strlen(findstr.getData()), replstr.getData());
  529.             //find next.
  530.             //delimPos = buf.find( delimiter.getData(), findPos);
  531.             delimPos = buf.find( delimiter.getData(), findPos + static_cast < string > (replstr.getData()).size() );
  532.             findPos = buf.find( findstr.getData(), findPos);
  533.         }
  534.     }
  535. }
  536. void
  537. StringData::lowercase()
  538. {
  539.     for(string::iterator i = buf.begin() ; 
  540. i != buf.end() ;
  541. ++i)
  542.     {
  543. #ifndef WIN32
  544. *i = std::tolower(*i);
  545. #else
  546. *i = tolower(*i);
  547. #endif
  548.     }
  549. }
  550. void 
  551. StringData::uppercase()
  552. {
  553.     for(string::iterator i = buf.begin() ; 
  554. i != buf.end() ;
  555. ++i)
  556.     {
  557. #ifndef WIN32
  558. *i = std::toupper(*i);
  559. #else
  560. *i = toupper(*i);
  561. #endif
  562.     }
  563. }
  564. StringData 
  565. StringData::parseOutsideQuotes(const char* match, 
  566.        bool useQuote,
  567.        bool useAngle,
  568.        bool* matchFail /* default argument */ )
  569. {
  570.     size_t pos = 0;
  571.     bool inDoubleQuotes = false;
  572.     bool inAngleBrackets = false;
  573.     bool foundAny = false;
  574.     size_t bufsize = buf.length();
  575.     while(!foundAny && (pos < bufsize))
  576.     {
  577. char p = buf[pos];
  578.         switch (p)
  579.         {
  580.         case '"':
  581.             if(!inAngleBrackets && useQuote)
  582.             {
  583.                 inDoubleQuotes = !inDoubleQuotes;
  584.             }
  585.             break;
  586.         case '<':
  587.             if(!inDoubleQuotes && useAngle)
  588.             {
  589.                 inAngleBrackets = true;
  590.             }
  591.             break;
  592.         case '>':
  593.             if(!inDoubleQuotes && useAngle)
  594.             {
  595.                 inAngleBrackets = false;
  596.             }
  597.             break;
  598.         default:
  599.             break;
  600.         }
  601. if(!inDoubleQuotes && !inAngleBrackets && isIn(p, match))
  602. {
  603.     foundAny = true;
  604. }
  605. pos++;
  606.     }
  607.     size_t pos2 = pos;
  608.     while(
  609. foundAny && 
  610. (pos2 < bufsize) && 
  611. isIn(buf[pos2], match)
  612. )
  613.     {
  614. pos2++;
  615.     }
  616.     StringData result;
  617.     if(foundAny)
  618.     {
  619. result = *this;
  620. result = buf.substr(0, pos - 1);
  621. buf = buf.substr(pos2, length());
  622. if(matchFail)
  623. {
  624.     *matchFail = false;
  625. }
  626.     }
  627.     else
  628.     {
  629. if(matchFail)
  630. {
  631.     *matchFail = true;
  632. }
  633.     }
  634.     return result;
  635. }
  636. StringData 
  637. StringData::parse(const char* match, bool* matchFail /* default argument */ )
  638. {
  639.     size_t pos = 0;
  640.     bool foundAny = false;
  641.     size_t bufsize = buf.length();
  642.     while(!foundAny && (pos < bufsize))
  643.     {
  644. char p = buf[pos];
  645. if(isIn(p, match))
  646. {
  647.     foundAny = true;
  648. }
  649. pos++;
  650.     }
  651.     size_t pos2 = pos;
  652.     while(
  653. foundAny && 
  654. (pos2 < bufsize) && 
  655. isIn(buf[pos2], match)
  656. )
  657.     {
  658. pos2++;
  659.     }
  660.     StringData result;
  661.     if(foundAny)
  662.     {
  663. result = buf.substr(0, pos - 1);
  664. buf = buf.substr(pos2, length());
  665. if(matchFail)
  666. {
  667.     *matchFail = false;
  668. }
  669.     }
  670.     else
  671.     {
  672. if(matchFail)
  673. {
  674.     *matchFail = true;
  675. }
  676.     }
  677.     return result;
  678. }
  679. StringData 
  680. StringData::matchChar(const char* match, 
  681.       char* matchedChar /* default argument */)
  682. {
  683.     size_t pos = 0;
  684.     bool foundAny = false;
  685.     size_t bufsize = buf.length();
  686.     while(!foundAny && (pos < bufsize))
  687.     {
  688. char p = buf[pos];
  689. if(isIn(p, match))
  690. {
  691.     foundAny = true;
  692.     if(matchedChar)
  693.     {
  694. *matchedChar = p;
  695.     }
  696. }
  697. pos++;
  698.     }
  699.     StringData result;
  700.     if(foundAny)
  701.     {
  702. result.buf = buf.substr(0, pos - 1);
  703. buf = buf.substr(pos, length());
  704.     }
  705.     else if(matchedChar)
  706.     {
  707. *matchedChar = '';
  708.     }
  709.     return result;
  710. }
  711. StringData 
  712. StringData::getLine(bool* matchFail /* default argument */ )
  713. {
  714.     const int STARTING = 0;
  715.     const int HAS_CR = 1;
  716.     const int HAS_LF = 2;
  717.     const int HAS_CRLF = 3;
  718.     int state = STARTING;
  719.     size_t pos = 0;
  720.     bool foundAny = false;
  721.     size_t bufsize = buf.length();
  722.     while(!foundAny && (pos < bufsize))
  723.     {
  724. char p = buf[pos];
  725. if( p == 'r' )
  726. {
  727.     state = HAS_CR;
  728. }
  729. else if (p == 'n' )
  730. {
  731.     if(state == HAS_CR)
  732.     {
  733. state = HAS_CRLF;
  734.     }
  735.     else
  736.     {
  737. state = HAS_LF;
  738.     }
  739.     foundAny = true;
  740. }
  741. else
  742. {
  743.     state = STARTING;
  744. }
  745. pos++;
  746.     }
  747.     int pos2 = pos;
  748.     if(state == HAS_CRLF)
  749.     {
  750. pos--;
  751.     }
  752.     StringData result;
  753.     if(foundAny)
  754.     {
  755. result.buf = buf.substr(0, pos - 1);
  756. buf = buf.substr(pos2, buf.length());
  757. if(matchFail)
  758. {
  759.     *matchFail = false;
  760. }
  761.     }
  762.     else
  763.     {
  764. if(matchFail)
  765. {
  766.     *matchFail = true;
  767. }
  768.     }
  769.     return result;
  770. }
  771. void 
  772. StringData::removeLWS()
  773. {
  774.     size_t replaceTo;
  775.     size_t pos;
  776.     pos = buf.find ("rn");
  777.     if (pos == string::npos)
  778.     {
  779.         pos = find("n");
  780.     }
  781.     else
  782.     {
  783. replaceTo = pos + 1; //should end after rn
  784.     }
  785.     if (pos == string::npos)
  786.     {
  787. return;
  788.     }
  789.     else
  790.     {
  791. replaceTo = pos; //should end after n
  792.     }
  793.     bool replaceFlag = false;
  794.     do
  795.     {
  796.         while ( (replaceTo + 1 < buf.length()) && 
  797.                 ( (buf[replaceTo+1] == 't') ||
  798.                   (buf[replaceTo+1] == ' ')
  799.                 ) 
  800.               )
  801.         {
  802.     char temp = buf[replaceTo];
  803.             replaceTo++;
  804.     temp = buf[replaceTo];
  805.             replaceFlag = true;
  806.         }
  807.         if (replaceFlag)
  808.         {
  809.             int replaceFrom = pos;
  810.             while ( (replaceFrom-1 > 0) &&
  811.                     ( (buf[replaceFrom-1] == 't') ||
  812.                       (buf[replaceFrom-1] == ' ')
  813.                     )
  814.                   )
  815.             {
  816.         char temp = buf[replaceFrom];
  817.                 replaceFrom--;
  818. temp = buf[replaceFrom];
  819.             }
  820.             int replaceNum = replaceTo - replaceFrom;
  821.             buf.replace(replaceFrom, replaceNum, ""); //replace with nothing
  822.    
  823.         }
  824.         //remember pos.
  825.         size_t initpos = pos;
  826.         pos = find("rn", initpos+2);
  827. if (pos > buf.length())
  828. {
  829.     pos = find("n", initpos+2);
  830.     replaceTo = pos;
  831.         }
  832. else
  833.         {
  834.     replaceTo = pos+1;
  835.         }
  836.     }
  837.     while (pos < buf.length());
  838. }
  839. ostream& 
  840. operator<<(ostream& s, const StringData& data)
  841. {
  842.     s << data.buf;
  843.     return s;
  844. }