Coverage Report

Created: 2025-12-31 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/rutil/ParseBuffer.cxx
Line
Count
Source
1
#include <ctype.h>
2
3
#include "rutil/ResipAssert.h"
4
5
#include "rutil/Logger.hxx"
6
#include "rutil/ParseBuffer.hxx"
7
#include "rutil/ParseException.hxx"
8
#include "rutil/DataStream.hxx"
9
#include "rutil/WinLeakCheck.hxx"
10
11
using namespace resip;
12
13
#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
14
15
const char* ParseBuffer::ParamTerm = ";?"; // maybe include "@>,"?
16
const char* ParseBuffer::Whitespace = " \t\r\n";
17
const Data ParseBuffer::Pointer::msg("dereferenced ParseBuffer eof");
18
19
ParseBuffer::ParseBuffer(const char* buff, size_t len, 
20
                         const Data& errorContext)
21
0
   : mBuff(buff),
22
0
     mPosition(buff),
23
0
     mEnd(buff+len),
24
0
     mErrorContext(errorContext)
25
0
{}
26
27
ParseBuffer::ParseBuffer(const char* buff, 
28
                         const Data& errorContext)
29
0
   : mBuff(buff),
30
0
     mPosition(buff),
31
0
     mEnd(buff+strlen(buff)),
32
0
     mErrorContext(errorContext)
33
0
{}
34
35
ParseBuffer::ParseBuffer(const Data& data,
36
            const Data& errorContext)
37
2
   : mBuff(data.data()),
38
2
     mPosition(mBuff),
39
2
     mEnd(mBuff + data.size()),
40
2
     mErrorContext(errorContext)
41
2
{}
42
43
ParseBuffer::ParseBuffer(const ParseBuffer& rhs)
44
0
   : mBuff(rhs.mBuff),
45
0
     mPosition(rhs.mPosition),
46
0
     mEnd(rhs.mEnd),
47
0
     mErrorContext(rhs.mErrorContext)
48
0
{}
49
50
ParseBuffer& 
51
ParseBuffer::operator=(const ParseBuffer& rhs)
52
0
{
53
0
   if (&rhs != this)
54
0
   {
55
0
      mBuff = rhs.mBuff;
56
0
      mPosition = rhs.mPosition;
57
0
      mEnd = rhs.mEnd;
58
0
   }
59
60
0
   return *this;
61
0
}
62
63
ParseBuffer::CurrentPosition
64
ParseBuffer::skipChar(char c)
65
0
{
66
0
   if (eof())
67
0
   {
68
0
      fail(__FILE__, __LINE__,"skipped over eof");
69
0
   }
70
0
   if (*mPosition != c)
71
0
   {
72
0
      Data msg("expected '");
73
0
      msg += c;
74
0
      msg += "'";
75
0
      fail(__FILE__, __LINE__,msg);
76
0
   }
77
0
   ++mPosition;
78
0
   return CurrentPosition(*this);
79
0
}
80
81
ParseBuffer::CurrentPosition
82
ParseBuffer::skipChars(const char* cs)
83
0
{
84
0
   const char* match = cs;
85
0
   while (*match != 0)
86
0
   {
87
0
      if (eof() || (*match != *mPosition))
88
0
      {
89
0
          Data msg("Expected \"");
90
0
          msg += cs;
91
0
          msg +=  "\"";
92
0
         fail(__FILE__, __LINE__,msg);
93
0
      }
94
0
      match++;
95
0
      mPosition++;
96
0
   }
97
0
   return CurrentPosition(*this);
98
0
}
99
100
ParseBuffer::CurrentPosition
101
ParseBuffer::skipChars(const Data& cs)
102
0
{
103
0
   const char* match = cs.data();
104
0
   for(Data::size_type i = 0; i < cs.size(); i++)
105
0
   {
106
0
      if (eof() || (*match != *mPosition))
107
0
      {
108
0
          Data msg( "Expected \"");
109
0
          msg += cs;
110
0
          msg += "\"";
111
0
         fail(__FILE__, __LINE__,msg);
112
0
      }
113
0
      match++;
114
0
      mPosition++;
115
0
   }
116
0
   return CurrentPosition(*this);
117
0
}
118
119
ParseBuffer::CurrentPosition
120
ParseBuffer::skipNonWhitespace()
121
0
{
122
0
   assertNotEof();
123
0
   while (mPosition < mEnd)
124
0
   {
125
0
      switch (*mPosition)
126
0
      {
127
0
         case ' ' :
128
0
         case '\t' : 
129
0
         case '\r' : 
130
0
         case '\n' : 
131
0
            return CurrentPosition(*this);
132
0
         default : 
133
0
            mPosition++;
134
0
      }
135
0
   }
136
0
   return CurrentPosition(*this);
137
0
}
138
139
ParseBuffer::CurrentPosition
140
ParseBuffer::skipWhitespace()
141
0
{
142
0
   while (mPosition < mEnd)
143
0
   {
144
0
      switch (*mPosition)
145
0
      {
146
0
         case ' ' :
147
0
         case '\t' : 
148
0
         case '\r' : 
149
0
         case '\n' : 
150
0
         {
151
0
            mPosition++;
152
0
            break;
153
0
         }
154
0
         default : 
155
0
            return CurrentPosition(*this);
156
0
      }
157
0
   }
158
0
   return CurrentPosition(*this);
159
0
}
160
161
// "SIP header field values can be folded onto multiple lines if the
162
//  continuation line begins with a space or horizontal tab"
163
164
// CR can be quote with \ within "" and comments -- treat \CR as whitespace
165
ParseBuffer::CurrentPosition
166
ParseBuffer::skipLWS()
167
0
{
168
0
   enum State {WS, CR, LF};
169
0
   State state = WS;
170
0
   while (mPosition < mEnd)
171
0
   {
172
0
      char c = *mPosition++;
173
0
      if (c == '\\')
174
0
      {
175
         // treat escaped CR and LF as space
176
0
         c = *mPosition++;
177
0
         if (c == '\r' || c == '\n')
178
0
         {
179
0
            c = ' ';
180
0
         }
181
0
      }
182
0
      switch (*mPosition++)
183
0
      {
184
0
         case ' ' :
185
0
         case '\t' : 
186
0
         {
187
0
            state = WS;
188
0
            break;
189
0
         }
190
0
         case '\r' : 
191
0
         {
192
0
            state = CR;
193
0
            break;
194
0
         }
195
0
         case '\n' : 
196
0
         {
197
0
            if (state == CR)
198
0
            {
199
0
               state = LF;
200
0
            }
201
0
            else
202
0
            {
203
0
               state = WS;
204
0
            }
205
0
            break;
206
0
         }
207
0
         default : 
208
0
         {
209
            // terminating CRLF not skipped
210
0
            if (state == LF)
211
0
            {
212
0
               mPosition -= 3;
213
0
            }
214
0
            else
215
0
            {
216
0
               mPosition--;
217
0
            }
218
0
            return CurrentPosition(*this);
219
0
         }
220
0
      }
221
0
   }
222
0
   return CurrentPosition(*this);
223
0
}
224
225
static Data CRLF("\r\n");
226
ParseBuffer::CurrentPosition
227
ParseBuffer::skipToTermCRLF()
228
0
{
229
0
   while (mPosition < mEnd)
230
0
   {
231
0
      skipToChars(CRLF);
232
0
      mPosition += 2;
233
0
      if ((*mPosition != ' ' &&
234
0
           *mPosition != '\t' &&
235
           // check for \CRLF -- not terminating
236
           //           \\CRLF -- terminating
237
0
           ((mPosition-3 < mBuff || *(mPosition-3) != '\\') ||
238
0
            (mPosition-4 > mBuff && *(mPosition-4) == '\\'))))
239
0
      {
240
0
         mPosition -= 2;
241
0
         return CurrentPosition(*this);
242
0
      }
243
0
   }
244
0
   return CurrentPosition(*this);
245
0
}
246
247
ParseBuffer::CurrentPosition
248
ParseBuffer::skipToChars(const char* cs)
249
0
{
250
0
   resip_assert(cs);
251
0
   unsigned int l = (unsigned int)strlen(cs);
252
253
0
   const char* rpos;
254
0
   const char* cpos;
255
   // Checking mPosition >= mEnd - l +1 is unnecessary because there won't be
256
   // enough bytes left to find [cs].
257
0
   while (mPosition < mEnd - l + 1)
258
0
   {
259
0
      rpos = mPosition;
260
0
      cpos = cs;
261
0
      for (unsigned int i = 0; i < l; i++)
262
0
      {
263
0
         if (*cpos++ != *rpos++)
264
0
         {
265
0
            mPosition++;
266
0
            goto skip;
267
0
         }
268
0
      }
269
0
      return CurrentPosition(*this);
270
0
     skip: ;
271
0
   }
272
   // Advance to the end since we didn't find a match.
273
0
   mPosition = mEnd;
274
0
   return CurrentPosition(*this);
275
0
}
276
277
ParseBuffer::CurrentPosition
278
ParseBuffer::skipToChars(const Data& sub)
279
0
{
280
0
   const char* begSub = sub.mBuf;
281
0
   const char* endSub = sub.mBuf + sub.mSize;
282
0
   if(begSub == endSub)
283
0
   {
284
0
      fail(__FILE__, __LINE__, "ParseBuffer::skipToChars() called with an "
285
0
                                 "empty string. Don't do this!");
286
0
   }
287
288
0
   while (true)
289
0
   {
290
0
next:
291
0
     const char* searchPos = mPosition;
292
0
     const char* subPos = sub.mBuf;
293
294
0
     while (subPos != endSub) 
295
0
     {
296
0
         if (searchPos == mEnd)
297
0
         {
298
            // nope
299
0
            mPosition = mEnd;
300
0
            return CurrentPosition(*this);
301
0
         }
302
0
         if (*subPos++ != *searchPos++)
303
0
         {
304
            // nope, but try the next position
305
0
            ++mPosition;
306
0
            goto next;
307
0
         }
308
0
     }
309
     // found a match
310
0
     return CurrentPosition(*this);
311
0
   }
312
0
}
313
314
bool 
315
ParseBuffer::oneOf(char c, const char* cs)
316
0
{
317
0
   while (*cs)
318
0
   {
319
0
      if (c == *(cs++))
320
0
      {
321
0
         return true;
322
0
      }
323
0
   }
324
0
   return false;
325
0
}
326
327
bool 
328
ParseBuffer::oneOf(char c, const Data& cs)
329
0
{
330
0
   for (Data::size_type i = 0; i < cs.size(); i++)
331
0
   {
332
0
      if (c == cs[i])
333
0
      {
334
0
         return true;
335
0
      }
336
0
   }
337
0
   return false;
338
0
}
339
340
ParseBuffer::CurrentPosition
341
ParseBuffer::skipToOneOf(const char* cs)
342
0
{
343
0
   while (mPosition < mEnd)
344
0
   {
345
0
      if (oneOf(*mPosition, cs))
346
0
      {
347
0
         return CurrentPosition(*this);
348
0
      }
349
0
      else
350
0
      {
351
0
         mPosition++;
352
0
      }
353
0
   }
354
0
   return CurrentPosition(*this);
355
0
}
356
357
ParseBuffer::CurrentPosition
358
ParseBuffer::skipToOneOf(const char* cs1,
359
                         const char* cs2)
360
0
{
361
0
   while (mPosition < mEnd)
362
0
   {
363
0
      if (oneOf(*mPosition, cs1) ||
364
0
          oneOf(*mPosition, cs2))
365
0
      {
366
0
         return CurrentPosition(*this);
367
0
      }
368
0
      else
369
0
      {
370
0
         mPosition++;
371
0
      }
372
0
   }
373
0
   return CurrentPosition(*this);
374
0
}
375
376
ParseBuffer::CurrentPosition
377
ParseBuffer::skipToOneOf(const Data& cs)
378
0
{
379
0
   while (mPosition < mEnd)
380
0
   {
381
0
      if (oneOf(*mPosition, cs))
382
0
      {
383
0
         return CurrentPosition(*this);
384
0
      }
385
0
      else
386
0
      {
387
0
         mPosition++;
388
0
      }
389
0
   }
390
0
   return CurrentPosition(*this);
391
0
}
392
393
ParseBuffer::CurrentPosition
394
ParseBuffer::skipToOneOf(const Data& cs1,
395
                         const Data& cs2)
396
0
{
397
0
   while (mPosition < mEnd)
398
0
   {
399
0
      if (oneOf(*mPosition, cs1) ||
400
0
          oneOf(*mPosition, cs2))
401
0
      {
402
0
         return CurrentPosition(*this);
403
0
      }
404
0
      else
405
0
      {
406
0
         mPosition++;
407
0
      }
408
0
   }
409
0
   return CurrentPosition(*this);
410
0
}
411
412
const char*
413
ParseBuffer::skipToEndQuote(char quote)
414
0
{
415
0
   while (mPosition < mEnd)
416
0
   {
417
      // !dlb! mark character encoding
418
0
      if (*mPosition == '\\')
419
0
      {
420
0
         mPosition += 2;
421
0
      }
422
0
      else if (*mPosition == quote)
423
0
      {
424
0
         return mPosition;
425
0
      }
426
0
      else
427
0
      {
428
0
         mPosition++;
429
0
      }
430
0
   }
431
432
0
   {
433
0
      Data msg("Missing '");
434
0
      msg += quote;
435
0
      msg += "'";
436
0
      fail(__FILE__,__LINE__,msg);
437
0
   }
438
0
   return 0;
439
0
}
440
441
const char*
442
ParseBuffer::skipBackChar()
443
0
{
444
0
   if (bof())
445
0
   {
446
0
      fail(__FILE__, __LINE__,"backed over beginning of buffer");
447
0
   }
448
0
   mPosition--;
449
0
   return mPosition;
450
0
}
451
452
const char*
453
ParseBuffer::skipBackWhitespace()
454
0
{
455
0
   while (!bof())
456
0
   {
457
0
      switch (*(--mPosition))
458
0
      {
459
0
         case ' ' :
460
0
         case '\t' : 
461
0
         case '\r' : 
462
0
         case '\n' : 
463
0
         {
464
0
            break;
465
0
         }
466
0
         default : 
467
0
            return ++mPosition;
468
0
      }
469
0
   }
470
0
   return mBuff;
471
0
}
472
473
// abcde
474
//     ^
475
// skipBackChar('d');
476
// abcde
477
//    ^
478
// skipChar('d');
479
// abcde
480
//     ^
481
const char*
482
ParseBuffer::skipBackChar(char c)
483
0
{
484
0
   if (bof())
485
0
   {
486
0
      fail(__FILE__, __LINE__,"backed over beginning of buffer");
487
0
   }
488
0
   if (*(--mPosition) != c)
489
0
   {
490
0
       Data msg( "Expected '");
491
0
       msg += c;
492
0
       msg += "'";
493
0
      fail(__FILE__, __LINE__,msg);
494
0
   }
495
0
   return mPosition;
496
0
}
497
498
// abcde
499
//      ^
500
// skipBackToChar('c');
501
// abcde
502
//    ^
503
const char*
504
ParseBuffer::skipBackToChar(char c)
505
2
{
506
18
   while (!bof())
507
18
   {
508
18
      if (*(--mPosition) == c)
509
2
      {
510
2
         return ++mPosition;
511
2
      }
512
18
   }
513
0
   return mBuff;
514
2
}
515
516
const char* 
517
ParseBuffer::skipBackToOneOf(const char* cs)
518
0
{
519
0
   while (!bof())
520
0
   {
521
0
      if (oneOf(*(--mPosition),cs))
522
0
      {
523
0
         return ++mPosition;
524
0
      }
525
0
   }
526
0
   return mBuff;
527
0
}
528
529
void
530
ParseBuffer::data(Data& data, const char* start) const
531
0
{
532
0
   if (!(mBuff <= start && start <= mPosition))
533
0
   {
534
0
      fail(__FILE__, __LINE__,"Bad anchor position");
535
0
   }
536
537
0
   if (data.mShareEnum == Data::Take)
538
0
   {
539
0
      delete[] data.mBuf;
540
0
   }
541
0
   data.mSize = (unsigned int)(mPosition - start);
542
0
   data.mBuf = const_cast<char*>(start);
543
0
   data.mCapacity = data.mSize;
544
0
   data.mShareEnum = Data::Share;
545
0
}
546
547
static const unsigned char hexToByte[256] = 
548
{
549
// 0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
550
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//0
551
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//1
552
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//2
553
   0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  'k','k','k','k','k','k', //3
554
   'k',0xA,0xB,0xC,0xD,0xE,0xF,'k','k','k','k','k','k','k','k','k', //4
555
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//5
556
   'k',0xA,0xB,0xC,0xD,0xE,0xF,'k','k','k','k','k','k','k','k','k', //6
557
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//8
558
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//9
559
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//a
560
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//b
561
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//c
562
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//d
563
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k',//e
564
   'k','k','k','k','k','k','k','k','k','k','k','k','k','k','k','k'   //f
565
566
};
567
568
void
569
ParseBuffer::dataUnescaped(Data& dataToUse, const char* start) const
570
0
{
571
0
   if (!(mBuff <= start && start <= mPosition))
572
0
   {
573
0
      fail(__FILE__, __LINE__, "Bad anchor position");
574
0
   }
575
576
0
   {
577
0
      const char* current = start;   
578
0
      while (current < mPosition)
579
0
      {
580
0
         if (*current == '%')
581
0
         {
582
            // needs to be unencoded
583
0
            goto copy;
584
0
         }
585
0
         current++;
586
0
      }
587
      // can use an overlay
588
0
      data(dataToUse, start);
589
0
      return;
590
0
   }
591
592
0
  copy:
593
0
   if ((size_t)(mPosition-start) > dataToUse.mCapacity)
594
0
   {
595
0
      dataToUse.resize((Data::size_type)(mPosition-start), false);
596
0
   }
597
598
0
   char* target = dataToUse.mBuf;
599
0
   const char* current = start;   
600
0
   while (current < mPosition)
601
0
   {
602
0
      if (*current == '%')
603
0
      {
604
0
         current++;
605
0
         if (mPosition - current < 2)
606
0
         {
607
0
            fail(__FILE__, __LINE__,"Illegal escaping");
608
0
         }
609
0
         const char high = hexToByte[(unsigned char)*current];
610
0
         const char low = hexToByte[(unsigned char)*(current + 1)];
611
0
         if (high!='k' && low!='k')
612
0
         {
613
0
            unsigned char escaped = 0;            
614
0
            escaped = high << 4 | low;
615
            // !bwc! I think this check is bogus, especially the ':' (58) check
616
            // You could maybe argue that the point of %-escaping is to allow
617
            // the use of UTF-8 data (including ASCII that is not allowed in an 
618
            // on-the-wire representation of whatever it is we're unescaping),
619
            // and not unprintable characters (the unprintable codes are not 
620
            // used by UTF-8). 
621
0
            if (escaped > 31 && escaped != 127 && escaped != 58)
622
0
            {
623
0
               *target++ = escaped;
624
0
               current+= 2;
625
0
            }
626
0
            else
627
0
            {
628
0
               *target++ = '%';
629
0
               *target++ = *current++;
630
0
               *target++ = *current++;
631
0
            }
632
0
         }
633
0
         else
634
0
         {
635
0
            fail(__FILE__, __LINE__,"Illegal escaping, not hex");
636
0
         }
637
0
      }
638
0
      else
639
0
      {
640
0
         *target++ = *current++;
641
0
      }
642
0
   }
643
0
   *target = 0;
644
0
   dataToUse.mSize = (Data::size_type)(target - dataToUse.mBuf);
645
0
}
646
647
Data
648
ParseBuffer::data(const char* start) const
649
0
{
650
0
   if (!(mBuff <= start && start <= mPosition))
651
0
   {
652
      
653
0
      fail(__FILE__, __LINE__,"Bad anchor position");
654
0
   }
655
656
0
   Data data(start, (Data::size_type)(mPosition - start));
657
0
   return data;
658
0
}
659
660
int
661
ParseBuffer::integer()
662
0
{
663
0
   if (this->eof())
664
0
   {
665
0
      fail(__FILE__, __LINE__,"Expected a digit, got eof ");
666
0
   }
667
668
0
   bool negative = false;
669
0
   if (*mPosition == '-')
670
0
   {
671
0
      negative = true;
672
0
      ++mPosition;
673
0
      assertNotEof();
674
0
   }
675
0
   else if (*mPosition == '+')
676
0
   {
677
0
      ++mPosition;
678
0
      assertNotEof();
679
0
   }
680
681
0
   if (!isdigit(static_cast< unsigned char >(*mPosition)))
682
0
   {
683
0
      Data msg("Expected a digit, got: ");
684
0
      msg += Data(mPosition, (Data::size_type)(mEnd - mPosition));
685
0
      fail(__FILE__, __LINE__,msg);
686
0
   }
687
688
#ifdef _MSC_VER
689
#pragma warning( push )
690
#pragma warning( disable : 4146)
691
#endif
692
   // The absolute value limit depending on the detected sign
693
0
   const unsigned int absoluteLimit = negative ? -(unsigned int)INT_MIN : INT_MAX;
694
   // maximum value for full number except last digit
695
0
   const unsigned int border = absoluteLimit / 10;
696
   // value the last digit must not exceed
697
0
   const unsigned int digitLimit = absoluteLimit % 10;
698
699
0
   unsigned int num = 0;
700
0
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
701
0
   {
702
0
      const unsigned int c = *mPosition++ - '0';
703
0
      if (num > border || (num == border && c > digitLimit)) {
704
0
         fail(__FILE__, __LINE__,"Overflow detected.");
705
0
      }
706
0
      num *= 10;
707
0
      num += c;
708
0
    }
709
0
    if (negative)
710
0
    {
711
0
        num = -num;
712
0
    }
713
0
    return num;
714
#ifdef _MSC_VER
715
#pragma warning( pop ) 
716
#endif
717
0
}
718
719
uint8_t
720
ParseBuffer::uInt8()
721
0
{
722
0
   const char* begin=mPosition;
723
0
   uint8_t num = 0;
724
0
   uint8_t last = 0;
725
0
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
726
0
   {
727
0
      last = num;
728
0
      num = num*10 + (*mPosition-'0');
729
0
      if(last>num)
730
0
      {
731
0
         fail(__FILE__, __LINE__,"Overflow detected.");
732
0
      }
733
0
      ++mPosition;
734
0
   }
735
   
736
0
   if(mPosition==begin)
737
0
   {
738
0
      fail(__FILE__, __LINE__,"Expected a digit");
739
0
   }
740
0
   return num;
741
0
}
742
743
744
//!dcm! -- merge these, ask about length checks
745
uint32_t
746
ParseBuffer::uInt32()
747
0
{
748
0
   const char* begin=mPosition;
749
0
   uint32_t num = 0;
750
0
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
751
0
   {
752
0
      num = num*10 + (*mPosition-'0');
753
0
      ++mPosition;
754
0
   }
755
756
0
   switch(mPosition-begin)
757
0
   {
758
0
      case 0:
759
0
         fail(__FILE__, __LINE__,"Expected a digit");
760
0
      case 1:
761
0
      case 2:
762
0
      case 3:
763
0
      case 4:
764
0
      case 5:
765
0
      case 6:
766
0
      case 7:
767
0
      case 8:
768
0
      case 9:
769
0
         break;
770
0
      case 10:
771
0
         if(*begin<'4')
772
0
         {
773
0
            break;
774
0
         }
775
0
         else if(*begin=='4' && num >= 4000000000UL)
776
0
         {
777
0
            break;
778
0
         }
779
0
      default:
780
0
         fail(__FILE__, __LINE__,"Overflow detected");
781
0
   }
782
783
0
   return num;
784
0
}
785
786
uint64_t
787
ParseBuffer::uInt64()
788
0
{
789
0
   const char* begin=mPosition;
790
0
   uint64_t num = 0;
791
0
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
792
0
   {
793
0
      num = num*10 + (*mPosition-'0');
794
0
      ++mPosition;
795
0
   }
796
797
0
   switch(mPosition-begin)
798
0
   {
799
0
      case 0:
800
0
         fail(__FILE__, __LINE__,"Expected a digit");
801
0
      case 1:
802
0
      case 2:
803
0
      case 3:
804
0
      case 4:
805
0
      case 5:
806
0
      case 6:
807
0
      case 7:
808
0
      case 8:
809
0
      case 9:
810
0
      case 10:
811
0
      case 11:
812
0
      case 12:
813
0
      case 13:
814
0
      case 14:
815
0
      case 15:
816
0
      case 16:
817
0
      case 17:
818
0
      case 18:
819
0
      case 19:
820
0
         break;
821
0
      case 20:
822
0
         if(*begin=='1' && num >= 10000000000000000000ULL)
823
0
         {
824
0
            break;
825
0
         }
826
0
      default:
827
0
         fail(__FILE__, __LINE__,"Overflow detected");
828
0
   }
829
830
0
   return num;
831
0
}
832
833
#ifndef RESIP_FIXED_POINT
834
float
835
ParseBuffer::floatVal()
836
0
{
837
0
   const char* s = mPosition;
838
0
   try
839
0
   {
840
0
      float mant = 0.0;
841
0
      int num = integer();
842
843
0
      if (*mPosition == '.')
844
0
      {
845
0
         skipChar();
846
0
         const char* pos = mPosition;
847
0
         mant = float(integer());
848
0
         int s = int(mPosition - pos);
849
0
         while (s--)
850
0
         {
851
0
            mant /= 10.0;
852
0
         }
853
0
      }
854
0
      return num + mant;
855
0
   }
856
0
   catch (ParseException&)
857
0
   {
858
0
      Data msg("Expected a floating point value, got: ");
859
0
      msg += Data(s, (Data::size_type)(mPosition - s));
860
0
      fail(__FILE__, __LINE__,msg);
861
0
      return 0.0;
862
0
   }
863
0
}
864
#endif
865
866
int
867
ParseBuffer::qVal()
868
0
{
869
   // parse a qvalue into an integer between 0 and 1000  (ex: 1.0 -> 1000,  0.8 -> 800, 0.05 -> 50)
870
0
   const char* s = mPosition;
871
0
   try
872
0
   {
873
0
      int num = integer();
874
0
      if (num == 1)
875
0
      {
876
0
         num = 1000;
877
0
      }
878
0
      else if (num != 0)
879
0
      {
880
         // error: qvalue must start with 1 or 0
881
0
         return 0;
882
0
      }
883
      
884
0
      if (!eof() && *mPosition == '.')
885
0
      {
886
0
         skipChar();
887
         
888
0
         int i = 100;
889
0
         while(!eof() && isdigit(static_cast< unsigned char >(*mPosition)) && i)
890
0
         {
891
0
            num += (*mPosition-'0') * i;
892
0
            i /= 10;
893
0
            skipChar();
894
0
         }
895
0
      }
896
0
      return num;
897
0
   }
898
0
   catch (ParseException&)
899
0
   {
900
0
      Data msg("Expected a floating point value, got: ");
901
0
      msg += Data(s, (Data::size_type)(mPosition - s));
902
0
      fail(__FILE__, __LINE__,msg);
903
0
      return 0;
904
0
   }
905
0
}
906
   
907
908
Data
909
spaces(unsigned int numSpaces)
910
0
{
911
0
   Data sps(numSpaces, Data::Preallocate);
912
0
   for (unsigned int i = 0; i < numSpaces; i++)
913
0
   {
914
0
      sps += ' ';
915
0
   }
916
0
   return sps;
917
0
}
918
919
Data 
920
escapeAndAnnotate(const char* buffer, 
921
                  Data::size_type size,
922
                  const char* position)
923
0
{ 
924
0
   Data ret(2*size+16, Data::Preallocate);
925
926
0
   const char* lastReturn = buffer;
927
0
   int lineCount = 0;
928
0
   bool doneAt = false;
929
930
0
   const char* p = buffer;
931
0
   for (unsigned int i = 0; i < size; i++)
932
0
   {
933
0
      unsigned char c = *p++;
934
935
0
      switch (c)
936
0
      {
937
0
         case 0x0D: // CR
938
0
         {
939
0
            continue;
940
0
         }
941
0
         case 0x0A: // LF
942
0
         {
943
0
            if (!doneAt && p >= position)
944
0
            {
945
0
               ret += "[CRLF]\n";
946
0
               ret += spaces((unsigned int)(position - lastReturn));
947
0
               ret += "^[CRLF]\n";
948
0
               doneAt = true;
949
0
            }
950
0
            else
951
0
            {
952
0
               lastReturn = p;
953
0
               ret += c;
954
0
            }
955
0
            lineCount++;
956
0
            continue;
957
0
         }
958
0
      }
959
960
0
      if (iscntrl(static_cast< unsigned char >(c)) || (c >= 0x7F))
961
0
      {
962
0
         ret +='*'; // indicates unprintable character
963
0
         continue;
964
0
      }
965
966
0
      ret += c;
967
0
   }
968
0
   if (!doneAt && p >= position)
969
0
   {
970
0
      ret += "\n";
971
0
      ret += spaces((unsigned int)(position - lastReturn));
972
0
      ret += "^\n";
973
0
   }
974
975
0
   return ret;
976
0
}
977
978
void
979
ParseBuffer::fail(const char* file, unsigned int line, const Data& detail) const
980
0
{
981
0
    Data errmsg;
982
0
    {
983
0
       DataStream ds(errmsg);
984
0
       ds << file << ":" << line
985
0
          << ", Parse failed ";
986
987
0
       if (detail != Data::Empty) ds << detail << ' ' ;
988
989
0
       ds << "in context: " << mErrorContext
990
0
          << std::endl
991
0
          << escapeAndAnnotate(mBuff, (Data::size_type)(mEnd - mBuff), mPosition);
992
          
993
0
       ds.flush();
994
0
   }
995
0
   DebugLog(<<errmsg);
996
0
   throw ParseException(errmsg, mErrorContext, file, line);
997
0
}
998
999
ParseBuffer::Pointer::Pointer(const ParseBuffer& pb,
1000
                              const char* position,
1001
                              bool atEof)
1002
0
   : mPb(pb),
1003
0
     mPosition(position),
1004
0
     mIsValid(!atEof)
1005
0
{}
1006
1007
ParseBuffer::Pointer::Pointer(const CurrentPosition& pos) :
1008
0
   mPb(pos.mPb),
1009
0
   mPosition(pos),
1010
0
   mIsValid(pos.mPb.valid())
1011
0
{}
1012
1013
const char& 
1014
ParseBuffer::Pointer::operator*() const
1015
0
{
1016
0
   if (mIsValid)
1017
0
   {
1018
0
      return *mPosition;
1019
0
   }
1020
0
   else
1021
0
   {
1022
0
      throw ParseException(msg, mPb.getContext(), __FILE__, __LINE__);
1023
0
   }
1024
0
}
1025
1026
/* ====================================================================
1027
 * The Vovida Software License, Version 1.0 
1028
 * 
1029
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
1030
 * 
1031
 * Redistribution and use in source and binary forms, with or without
1032
 * modification, are permitted provided that the following conditions
1033
 * are met:
1034
 * 
1035
 * 1. Redistributions of source code must retain the above copyright
1036
 *    notice, this list of conditions and the following disclaimer.
1037
 * 
1038
 * 2. Redistributions in binary form must reproduce the above copyright
1039
 *    notice, this list of conditions and the following disclaimer in
1040
 *    the documentation and/or other materials provided with the
1041
 *    distribution.
1042
 * 
1043
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1044
 *    and "Vovida Open Communication Application Library (VOCAL)" must
1045
 *    not be used to endorse or promote products derived from this
1046
 *    software without prior written permission. For written
1047
 *    permission, please contact vocal@vovida.org.
1048
 *
1049
 * 4. Products derived from this software may not be called "VOCAL", nor
1050
 *    may "VOCAL" appear in their name, without prior written
1051
 *    permission of Vovida Networks, Inc.
1052
 * 
1053
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1054
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1055
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1056
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1057
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1058
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1059
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1060
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1061
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1062
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1063
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1064
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1065
 * DAMAGE.
1066
 * 
1067
 * ====================================================================
1068
 * 
1069
 * This software consists of voluntary contributions made by Vovida
1070
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1071
 * Inc.  For more information on Vovida Networks, Inc., please see
1072
 * <http://www.vovida.org/>.
1073
 *
1074
 */