reSIProcate/rutil  9694
ParseBuffer.cxx
Go to the documentation of this file.
00001 #include <cassert>
00002 
00003 #include "rutil/Logger.hxx"
00004 #include "rutil/ParseBuffer.hxx"
00005 #include "rutil/ParseException.hxx"
00006 #include "rutil/DataStream.hxx"
00007 #include "rutil/WinLeakCheck.hxx"
00008 
00009 using namespace resip;
00010 
00011 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
00012 
00013 const char* ParseBuffer::ParamTerm = ";?"; // maybe include "@>,"?
00014 const char* ParseBuffer::Whitespace = " \t\r\n";
00015 const Data ParseBuffer::Pointer::msg("dereferenced ParseBuffer eof");
00016 
00017 ParseBuffer::ParseBuffer(const char* buff, size_t len, 
00018                          const Data& errorContext)
00019    : mBuff(buff),
00020      mPosition(buff),
00021      mEnd(buff+len),
00022      mErrorContext(errorContext)
00023 {}
00024 
00025 ParseBuffer::ParseBuffer(const Data& data,
00026             const Data& errorContext)
00027    : mBuff(data.data()),
00028      mPosition(mBuff),
00029      mEnd(mBuff + data.size()),
00030      mErrorContext(errorContext)
00031 {}
00032 
00033 ParseBuffer::ParseBuffer(const ParseBuffer& rhs)
00034    : mBuff(rhs.mBuff),
00035      mPosition(rhs.mPosition),
00036      mEnd(rhs.mEnd),
00037      mErrorContext(rhs.mErrorContext)
00038 {}
00039 
00040 ParseBuffer& 
00041 ParseBuffer::operator=(const ParseBuffer& rhs)
00042 {
00043    mBuff = rhs.mBuff;
00044    mPosition = rhs.mPosition;
00045    mEnd = rhs.mEnd;
00046 
00047    return *this;
00048 }
00049 
00050 ParseBuffer::CurrentPosition
00051 ParseBuffer::skipChar(char c)
00052 {
00053    if (eof())
00054    {
00055       fail(__FILE__, __LINE__,"skipped over eof");
00056    }
00057    if (*mPosition != c)
00058    {
00059       Data msg("expected '");
00060       msg += c;
00061       msg += "'";
00062       fail(__FILE__, __LINE__,msg);
00063    }
00064    ++mPosition;
00065    return CurrentPosition(*this);
00066 }
00067 
00068 ParseBuffer::CurrentPosition
00069 ParseBuffer::skipChars(const char* cs)
00070 {
00071    const char* match = cs;
00072    while (*match != 0)
00073    {
00074       if (eof() || (*match != *mPosition))
00075       {
00076           Data msg("Expected \"");
00077           msg += cs;
00078           msg +=  "\"";
00079          fail(__FILE__, __LINE__,msg);
00080       }
00081       match++;
00082       mPosition++;
00083    }
00084    return CurrentPosition(*this);
00085 }
00086 
00087 ParseBuffer::CurrentPosition
00088 ParseBuffer::skipChars(const Data& cs)
00089 {
00090    const char* match = cs.data();
00091    for(Data::size_type i = 0; i < cs.size(); i++)
00092    {
00093       if (eof() || (*match != *mPosition))
00094       {
00095           Data msg( "Expected \"");
00096           msg += cs;
00097           msg += "\"";
00098          fail(__FILE__, __LINE__,msg);
00099       }
00100       match++;
00101       mPosition++;
00102    }
00103    return CurrentPosition(*this);
00104 }
00105 
00106 ParseBuffer::CurrentPosition
00107 ParseBuffer::skipNonWhitespace()
00108 {
00109    assertNotEof();
00110    while (mPosition < mEnd)
00111    {
00112       switch (*mPosition)
00113       {
00114          case ' ' :
00115          case '\t' : 
00116          case '\r' : 
00117          case '\n' : 
00118             return CurrentPosition(*this);
00119          default : 
00120             mPosition++;
00121       }
00122    }
00123    return CurrentPosition(*this);
00124 }
00125 
00126 ParseBuffer::CurrentPosition
00127 ParseBuffer::skipWhitespace()
00128 {
00129    while (mPosition < mEnd)
00130    {
00131       switch (*mPosition)
00132       {
00133          case ' ' :
00134          case '\t' : 
00135          case '\r' : 
00136          case '\n' : 
00137          {
00138             mPosition++;
00139             break;
00140          }
00141          default : 
00142             return CurrentPosition(*this);
00143       }
00144    }
00145    return CurrentPosition(*this);
00146 }
00147 
00148 // "SIP header field values can be folded onto multiple lines if the
00149 //  continuation line begins with a space or horizontal tab"
00150 
00151 // CR can be quote with \ within "" and comments -- treat \CR as whitespace
00152 ParseBuffer::CurrentPosition
00153 ParseBuffer::skipLWS()
00154 {
00155    enum State {WS, CR, LF};
00156    State state = WS;
00157    while (mPosition < mEnd)
00158    {
00159       char c = *mPosition++;
00160       if (c == '\\')
00161       {
00162          // treat escaped CR and LF as space
00163          c = *mPosition++;
00164          if (c == '\r' || c == '\n')
00165          {
00166             c = ' ';
00167          }
00168       }
00169       switch (*mPosition++)
00170       {
00171          case ' ' :
00172          case '\t' : 
00173          {
00174             state = WS;
00175             break;
00176          }
00177          case '\r' : 
00178          {
00179             state = CR;
00180             break;
00181          }
00182          case '\n' : 
00183          {
00184             if (state == CR)
00185             {
00186                state = LF;
00187             }
00188             else
00189             {
00190                state = WS;
00191             }
00192             break;
00193          }
00194          default : 
00195          {
00196             // terminating CRLF not skipped
00197             if (state == LF)
00198             {
00199                mPosition -= 3;
00200             }
00201             else
00202             {
00203                mPosition--;
00204             }
00205             return CurrentPosition(*this);
00206          }
00207       }
00208    }
00209    return CurrentPosition(*this);
00210 }
00211 
00212 static Data CRLF("\r\n");
00213 ParseBuffer::CurrentPosition
00214 ParseBuffer::skipToTermCRLF()
00215 {
00216    while (mPosition < mEnd)
00217    {
00218       skipToChars(CRLF);
00219       mPosition += 2;
00220       if ((*mPosition != ' ' &&
00221            *mPosition != '\t' &&
00222            // check for \CRLF -- not terminating
00223            //           \\CRLF -- terminating
00224            ((mPosition-3 < mBuff || *(mPosition-3) != '\\') ||
00225             (mPosition-4 > mBuff && *(mPosition-4) == '\\'))))
00226       {
00227          mPosition -= 2;
00228          return CurrentPosition(*this);
00229       }
00230    }
00231    return CurrentPosition(*this);
00232 }
00233 
00234 ParseBuffer::CurrentPosition
00235 ParseBuffer::skipToChars(const char* cs)
00236 {
00237    assert(cs);
00238    unsigned int l = (unsigned int)strlen(cs);
00239 
00240    const char* rpos;
00241    const char* cpos;
00242    while (mPosition < mEnd)
00243    {
00244       rpos = mPosition;
00245       cpos = cs;
00246       for (unsigned int i = 0; i < l; i++)
00247       {
00248          if (*cpos++ != *rpos++)
00249          {
00250             mPosition++;
00251             goto skip;
00252          }
00253       }
00254       return CurrentPosition(*this);
00255      skip: ;
00256    }
00257    return CurrentPosition(*this);
00258 }
00259 
00260 ParseBuffer::CurrentPosition
00261 ParseBuffer::skipToChars(const Data& sub)
00262 {
00263    const char* begSub = sub.mBuf;
00264    const char* endSub = sub.mBuf + sub.mSize;
00265    if(begSub == endSub)
00266    {
00267       fail(__FILE__, __LINE__, "ParseBuffer::skipToChars() called with an "
00268                                  "empty string. Don't do this!");
00269    }
00270 
00271    while (true)
00272    {
00273 next:
00274      const char* searchPos = mPosition;
00275      const char* subPos = sub.mBuf;
00276 
00277      while (subPos != endSub) 
00278      {
00279          if (searchPos == mEnd)
00280          {
00281             // nope
00282             mPosition = mEnd;
00283             return CurrentPosition(*this);
00284          }
00285          if (*subPos++ != *searchPos++)
00286          {
00287             // nope, but try the next position
00288             ++mPosition;
00289             goto next;
00290          }
00291      }
00292      // found a match
00293      return CurrentPosition(*this);
00294    }
00295 }
00296 
00297 bool 
00298 ParseBuffer::oneOf(char c, const char* cs)
00299 {
00300    while (*cs)
00301    {
00302       if (c == *(cs++))
00303       {
00304          return true;
00305       }
00306    }
00307    return false;
00308 }
00309 
00310 bool 
00311 ParseBuffer::oneOf(char c, const Data& cs)
00312 {
00313    for (Data::size_type i = 0; i < cs.size(); i++)
00314    {
00315       if (c == cs[i])
00316       {
00317          return true;
00318       }
00319    }
00320    return false;
00321 }
00322 
00323 ParseBuffer::CurrentPosition
00324 ParseBuffer::skipToOneOf(const char* cs)
00325 {
00326    while (mPosition < mEnd)
00327    {
00328       if (oneOf(*mPosition, cs))
00329       {
00330          return CurrentPosition(*this);
00331       }
00332       else
00333       {
00334          mPosition++;
00335       }
00336    }
00337    return CurrentPosition(*this);
00338 }
00339 
00340 ParseBuffer::CurrentPosition
00341 ParseBuffer::skipToOneOf(const char* cs1,
00342                          const char* cs2)
00343 {
00344    while (mPosition < mEnd)
00345    {
00346       if (oneOf(*mPosition, cs1) ||
00347           oneOf(*mPosition, cs2))
00348       {
00349          return CurrentPosition(*this);
00350       }
00351       else
00352       {
00353          mPosition++;
00354       }
00355    }
00356    return CurrentPosition(*this);
00357 }
00358 
00359 ParseBuffer::CurrentPosition
00360 ParseBuffer::skipToOneOf(const Data& cs)
00361 {
00362    while (mPosition < mEnd)
00363    {
00364       if (oneOf(*mPosition, cs))
00365       {
00366          return CurrentPosition(*this);
00367       }
00368       else
00369       {
00370          mPosition++;
00371       }
00372    }
00373    return CurrentPosition(*this);
00374 }
00375 
00376 ParseBuffer::CurrentPosition
00377 ParseBuffer::skipToOneOf(const Data& cs1,
00378                          const Data& cs2)
00379 {
00380    while (mPosition < mEnd)
00381    {
00382       if (oneOf(*mPosition, cs1) ||
00383           oneOf(*mPosition, cs2))
00384       {
00385          return CurrentPosition(*this);
00386       }
00387       else
00388       {
00389          mPosition++;
00390       }
00391    }
00392    return CurrentPosition(*this);
00393 }
00394 
00395 const char*
00396 ParseBuffer::skipToEndQuote(char quote)
00397 {
00398    while (mPosition < mEnd)
00399    {
00400       // !dlb! mark character encoding
00401       if (*mPosition == '\\')
00402       {
00403          mPosition += 2;
00404       }
00405       else if (*mPosition == quote)
00406       {
00407          return mPosition;
00408       }
00409       else
00410       {
00411          mPosition++;
00412       }
00413    }
00414 
00415    {
00416       Data msg("Missing '");
00417       msg += quote;
00418       msg += "'";
00419       fail(__FILE__,__LINE__,msg);
00420    }
00421    return 0;
00422 }
00423 
00424 const char*
00425 ParseBuffer::skipBackChar()
00426 {
00427    if (bof())
00428    {
00429       fail(__FILE__, __LINE__,"backed over beginning of buffer");
00430    }
00431    mPosition--;
00432    return mPosition;
00433 }
00434 
00435 const char*
00436 ParseBuffer::skipBackWhitespace()
00437 {
00438    while (!bof())
00439    {
00440       switch (*(--mPosition))
00441       {
00442          case ' ' :
00443          case '\t' : 
00444          case '\r' : 
00445          case '\n' : 
00446          {
00447             break;
00448          }
00449          default : 
00450             return ++mPosition;
00451       }
00452    }
00453    return mBuff;
00454 }
00455 
00456 // abcde
00457 //     ^
00458 // skipBackChar('d');
00459 // abcde
00460 //    ^
00461 // skipChar('d');
00462 // abcde
00463 //     ^
00464 const char*
00465 ParseBuffer::skipBackChar(char c)
00466 {
00467    if (bof())
00468    {
00469       fail(__FILE__, __LINE__,"backed over beginning of buffer");
00470    }
00471    if (*(--mPosition) != c)
00472    {
00473        Data msg( "Expected '");
00474        msg += c;
00475        msg += "'";
00476       fail(__FILE__, __LINE__,msg);
00477    }
00478    return mPosition;
00479 }
00480 
00481 // abcde
00482 //      ^
00483 // skipBackToChar('c');
00484 // abcde
00485 //    ^
00486 const char*
00487 ParseBuffer::skipBackToChar(char c)
00488 {
00489    while (!bof())
00490    {
00491       if (*(--mPosition) == c)
00492       {
00493          return ++mPosition;
00494       }
00495    }
00496    return mBuff;
00497 }
00498 
00499 const char* 
00500 ParseBuffer::skipBackToOneOf(const char* cs)
00501 {
00502    while (!bof())
00503    {
00504       if (oneOf(*(--mPosition),cs))
00505       {
00506          return ++mPosition;
00507       }
00508    }
00509    return mBuff;
00510 }
00511 
00512 void
00513 ParseBuffer::data(Data& data, const char* start) const
00514 {
00515    if (!(mBuff <= start && start <= mPosition))
00516    {
00517       fail(__FILE__, __LINE__,"Bad anchor position");
00518    }
00519 
00520    if (data.mShareEnum == Data::Take)
00521    {
00522       delete[] data.mBuf;
00523    }
00524    data.mSize = (unsigned int)(mPosition - start);
00525    data.mBuf = const_cast<char*>(start);
00526    data.mCapacity = data.mSize;
00527    data.mShareEnum = Data::Share;
00528 }
00529 
00530 static const unsigned char hexToByte[256] = 
00531 {
00532 // 0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
00533    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//0
00534    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//1
00535    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//2
00536    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  'k','k','k','k','k','k', //3
00537    'k',0xA,0xB,0xC,0xD,0xE,0xF,'k','k','k','k','k','k','k','k','k', //4
00538    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//5
00539    'k',0xA,0xB,0xC,0xD,0xE,0xF,'k','k','k','k','k','k','k','k','k', //6
00540    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//8
00541    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//9
00542    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//a
00543    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//b
00544    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//c
00545    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//d
00546    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//e
00547    'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k'   //f
00548 
00549 };
00550 
00551 void
00552 ParseBuffer::dataUnescaped(Data& dataToUse, const char* start) const
00553 {
00554    if (!(mBuff <= start && start <= mPosition))
00555    {
00556       fail(__FILE__, __LINE__, "Bad anchor position");
00557    }
00558 
00559    {
00560       const char* current = start;   
00561       while (current < mPosition)
00562       {
00563          if (*current == '%')
00564          {
00565             // needs to be unencoded
00566             goto copy;
00567          }
00568          current++;
00569       }
00570       // can use an overlay
00571       data(dataToUse, start);
00572       return;
00573    }
00574 
00575   copy:
00576    if ((size_t)(mPosition-start) > dataToUse.mCapacity)
00577    {
00578       dataToUse.resize(mPosition-start, false);
00579    }
00580 
00581    char* target = dataToUse.mBuf;
00582    const char* current = start;   
00583    while (current < mPosition)
00584    {
00585       if (*current == '%')
00586       {
00587          current++;
00588          if (mPosition - current < 2)
00589          {
00590             fail(__FILE__, __LINE__,"Illegal escaping");
00591          }
00592          const char high = hexToByte[(unsigned char)*current];
00593          const char low = hexToByte[(unsigned char)*(current + 1)];
00594          if (high!='k' && low!='k')
00595          {
00596             unsigned char escaped = 0;            
00597             escaped = high << 4 | low;
00598             // !bwc! I think this check is bogus, especially the ':' (58) check
00599             // You could maybe argue that the point of %-escaping is to allow
00600             // the use of UTF-8 data (including ASCII that is not allowed in an 
00601             // on-the-wire representation of whatever it is we're unescaping),
00602             // and not unprintable characters (the unprintable codes are not 
00603             // used by UTF-8). 
00604             if (escaped > 31 && escaped != 127 && escaped != 58)
00605             {
00606                *target++ = escaped;
00607                current+= 2;
00608             }
00609             else
00610             {
00611                *target++ = '%';
00612                *target++ = *current++;
00613                *target++ = *current++;
00614             }
00615          }
00616          else
00617          {
00618             fail(__FILE__, __LINE__,"Illegal escaping, not hex");
00619          }
00620       }
00621       else
00622       {
00623          *target++ = *current++;
00624       }
00625    }
00626    *target = 0;
00627    dataToUse.mSize = target - dataToUse.mBuf;   
00628 }
00629 
00630 Data
00631 ParseBuffer::data(const char* start) const
00632 {
00633    if (!(mBuff <= start && start <= mPosition))
00634    {
00635       
00636       fail(__FILE__, __LINE__,"Bad anchor position");
00637    }
00638 
00639    Data data(start, mPosition - start);
00640    return data;
00641 }
00642 
00643 int
00644 ParseBuffer::integer()
00645 {
00646    if (this->eof())
00647    {
00648       fail(__FILE__, __LINE__,"Expected a digit, got eof ");
00649    }
00650 
00651    int signum = 1;
00652    if (*mPosition == '-')
00653    {
00654       signum = -1;
00655       ++mPosition;
00656       assertNotEof();
00657    }
00658    else if (*mPosition == '+')
00659    {
00660       ++mPosition;
00661       assertNotEof();
00662    }
00663 
00664    if (!isdigit(*mPosition))
00665    {
00666        Data msg("Expected a digit, got: ");
00667        msg += Data(mPosition, (mEnd - mPosition));
00668       fail(__FILE__, __LINE__,msg);
00669    }
00670    
00671    int num = 0;
00672    int last=0;
00673    while (!eof() && isdigit(*mPosition))
00674    {
00675       last=num;
00676       num = num*10 + (*mPosition-'0');
00677       if(last > num)
00678       {
00679          fail(__FILE__, __LINE__,"Overflow detected.");
00680       }
00681       ++mPosition;
00682    }
00683    
00684    return signum*num;
00685 }
00686 
00687 UInt8
00688 ParseBuffer::uInt8()
00689 {
00690    const char* begin=mPosition;
00691    UInt8 num = 0;
00692    UInt8 last = 0;
00693    while (!eof() && isdigit(*mPosition))
00694    {
00695       last = num;
00696       num = num*10 + (*mPosition-'0');
00697       if(last>num)
00698       {
00699          fail(__FILE__, __LINE__,"Overflow detected.");
00700       }
00701       ++mPosition;
00702    }
00703    
00704    if(mPosition==begin)
00705    {
00706       fail(__FILE__, __LINE__,"Expected a digit");
00707    }
00708    return num;
00709 }
00710 
00711 
00713 UInt32
00714 ParseBuffer::uInt32()
00715 {
00716    const char* begin=mPosition;
00717    UInt32 num = 0;
00718    while (!eof() && isdigit(*mPosition))
00719    {
00720       num = num*10 + (*mPosition-'0');
00721       ++mPosition;
00722    }
00723 
00724    switch(mPosition-begin)
00725    {
00726       case 0:
00727          fail(__FILE__, __LINE__,"Expected a digit");
00728       case 1:
00729       case 2:
00730       case 3:
00731       case 4:
00732       case 5:
00733       case 6:
00734       case 7:
00735       case 8:
00736       case 9:
00737          break;
00738       case 10:
00739          if(*begin<'4')
00740          {
00741             break;
00742          }
00743          else if(*begin=='4' && num >= 4000000000UL)
00744          {
00745             break;
00746          }
00747       default:
00748          fail(__FILE__, __LINE__,"Overflow detected");
00749    }
00750 
00751    return num;
00752 }
00753 
00754 UInt64
00755 ParseBuffer::uInt64()
00756 {
00757    const char* begin=mPosition;
00758    UInt64 num = 0;
00759    while (!eof() && isdigit(*mPosition))
00760    {
00761       num = num*10 + (*mPosition-'0');
00762       ++mPosition;
00763    }
00764 
00765    switch(mPosition-begin)
00766    {
00767       case 0:
00768          fail(__FILE__, __LINE__,"Expected a digit");
00769       case 1:
00770       case 2:
00771       case 3:
00772       case 4:
00773       case 5:
00774       case 6:
00775       case 7:
00776       case 8:
00777       case 9:
00778       case 10:
00779       case 11:
00780       case 12:
00781       case 13:
00782       case 14:
00783       case 15:
00784       case 16:
00785       case 17:
00786       case 18:
00787       case 19:
00788          break;
00789       case 20:
00790          if(*begin=='1' && num >= 10000000000000000000ULL)
00791          {
00792             break;
00793          }
00794       default:
00795          fail(__FILE__, __LINE__,"Overflow detected");
00796    }
00797 
00798    return num;
00799 }
00800 
00801 #ifndef RESIP_FIXED_POINT
00802 float
00803 ParseBuffer::floatVal()
00804 {
00805    const char* s = mPosition;
00806    try
00807    {
00808       float mant = 0.0;
00809       int num = integer();
00810 
00811       if (*mPosition == '.')
00812       {
00813          skipChar();
00814          const char* pos = mPosition;
00815          mant = float(integer());
00816          int s = int(mPosition - pos);
00817          while (s--)
00818          {
00819             mant /= 10.0;
00820          }
00821       }
00822       return num + mant;
00823    }
00824    catch (ParseException&)
00825    {
00826       Data msg("Expected a floating point value, got: ");
00827       msg += Data(s, mPosition - s);
00828       fail(__FILE__, __LINE__,msg);
00829       return 0.0;
00830    }
00831 }
00832 #endif
00833 
00834 int
00835 ParseBuffer::qVal()
00836 {
00837    // parse a qvalue into an integer between 0 and 1000  (ex: 1.0 -> 1000,  0.8 -> 800, 0.05 -> 50)
00838    const char* s = mPosition;
00839    try
00840    {
00841       int num = integer();
00842       if (num == 1)
00843       {
00844          num = 1000;
00845       }
00846       else if (num != 0)
00847       {
00848          // error: qvalue must start with 1 or 0
00849          return 0;
00850       }
00851       
00852       if (*mPosition == '.')
00853       {
00854          skipChar();
00855          
00856          int i = 100;
00857          while(!eof() && isdigit(*mPosition) && i)
00858          {
00859             num += (*mPosition-'0') * i;
00860             i /= 10;
00861             skipChar();
00862          }
00863       }
00864       return num;
00865    }
00866    catch (ParseException&)
00867    {
00868       Data msg("Expected a floating point value, got: ");
00869       msg += Data(s, mPosition - s);
00870       fail(__FILE__, __LINE__,msg);
00871       return 0;
00872    }
00873 }
00874    
00875 
00876 Data
00877 spaces(unsigned int numSpaces)
00878 {
00879    Data sps(numSpaces, Data::Preallocate);
00880    for (unsigned int i = 0; i < numSpaces; i++)
00881    {
00882       sps += ' ';
00883    }
00884    return sps;
00885 }
00886 
00887 Data 
00888 escapeAndAnnotate(const char* buffer, 
00889                   Data::size_type size,
00890                   const char* position)
00891 { 
00892    Data ret(2*size+16, Data::Preallocate);
00893 
00894    const char* lastReturn = buffer;
00895    int lineCount = 0;
00896    bool doneAt = false;
00897 
00898    const char* p = buffer;
00899    for (unsigned int i = 0; i < size; i++)
00900    {
00901       unsigned char c = *p++;
00902 
00903       switch (c)
00904       {
00905          case 0x0D: // CR
00906          {
00907             continue;
00908          }
00909          case 0x0A: // LF
00910          {
00911             if (!doneAt && p >= position)
00912             {
00913                ret += "[CRLF]\n";
00914                ret += spaces((unsigned int)(position - lastReturn));
00915                ret += "^[CRLF]\n";
00916                doneAt = true;
00917             }
00918             else
00919             {
00920                lastReturn = p;
00921                ret += c;
00922             }
00923             lineCount++;
00924             continue;
00925          }
00926       }
00927       
00928       if (iscntrl(c) || (c >= 0x7F))
00929       {
00930          ret +='*'; // indicates unprintable character
00931          continue;
00932       }
00933 
00934       ret += c;
00935    }
00936    if (!doneAt && p >= position)
00937    {
00938       ret += "\n";
00939       ret += spaces((unsigned int)(position - lastReturn));
00940       ret += "^\n";
00941    }
00942 
00943    return ret;
00944 }
00945 
00946 void
00947 ParseBuffer::fail(const char* file, unsigned int line, const Data& detail) const
00948 {
00949     Data errmsg;
00950     {
00951        DataStream ds(errmsg);
00952        ds << file << ":" << line
00953           << ", Parse failed ";
00954 
00955        if (detail != Data::Empty) ds << detail << ' ' ;
00956 
00957        ds << "in context: " << mErrorContext
00958           << std::endl
00959           << escapeAndAnnotate(mBuff, mEnd - mBuff, mPosition);
00960           
00961        ds.flush();
00962    }
00963    DebugLog(<<errmsg);
00964    throw ParseException(errmsg, mErrorContext, file, line);
00965 }
00966 
00967 ParseBuffer::Pointer::Pointer(const ParseBuffer& pb,
00968                               const char* position,
00969                               bool atEof)
00970    : mPb(pb),
00971      mPosition(position),
00972      mIsValid(!atEof)
00973 {}
00974 
00975 ParseBuffer::Pointer::Pointer(const CurrentPosition& pos) :
00976    mPb(pos.mPb),
00977    mPosition(pos),
00978    mIsValid(pos.mPb.valid())
00979 {}
00980 
00981 const char& 
00982 ParseBuffer::Pointer::operator*() const
00983 {
00984    if (mIsValid)
00985    {
00986       return *mPosition;
00987    }
00988    else
00989    {
00990       throw ParseException(msg, mPb.getContext(), __FILE__, __LINE__);
00991    }
00992 }
00993 
00994 /* ====================================================================
00995  * The Vovida Software License, Version 1.0 
00996  * 
00997  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00998  * 
00999  * Redistribution and use in source and binary forms, with or without
01000  * modification, are permitted provided that the following conditions
01001  * are met:
01002  * 
01003  * 1. Redistributions of source code must retain the above copyright
01004  *    notice, this list of conditions and the following disclaimer.
01005  * 
01006  * 2. Redistributions in binary form must reproduce the above copyright
01007  *    notice, this list of conditions and the following disclaimer in
01008  *    the documentation and/or other materials provided with the
01009  *    distribution.
01010  * 
01011  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
01012  *    and "Vovida Open Communication Application Library (VOCAL)" must
01013  *    not be used to endorse or promote products derived from this
01014  *    software without prior written permission. For written
01015  *    permission, please contact vocal@vovida.org.
01016  *
01017  * 4. Products derived from this software may not be called "VOCAL", nor
01018  *    may "VOCAL" appear in their name, without prior written
01019  *    permission of Vovida Networks, Inc.
01020  * 
01021  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
01022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
01023  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
01024  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
01025  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
01026  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
01027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
01028  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
01029  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
01030  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
01031  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
01032  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
01033  * DAMAGE.
01034  * 
01035  * ====================================================================
01036  * 
01037  * This software consists of voluntary contributions made by Vovida
01038  * Networks, Inc. and many individuals on behalf of Vovida Networks,
01039  * Inc.  For more information on Vovida Networks, Inc., please see
01040  * <http://www.vovida.org/>.
01041  *
01042  */