Coverage Report

Created: 2026-02-14 06:40

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
156k
   : mBuff(buff),
22
156k
     mPosition(buff),
23
156k
     mEnd(buff+len),
24
156k
     mErrorContext(errorContext)
25
156k
{}
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
688
   : mBuff(data.data()),
38
688
     mPosition(mBuff),
39
688
     mEnd(mBuff + data.size()),
40
688
     mErrorContext(errorContext)
41
688
{}
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
3.48M
{
66
3.48M
   if (eof())
67
3.04k
   {
68
3.04k
      fail(__FILE__, __LINE__,"skipped over eof");
69
3.04k
   }
70
3.48M
   if (*mPosition != c)
71
17.0k
   {
72
17.0k
      Data msg("expected '");
73
17.0k
      msg += c;
74
17.0k
      msg += "'";
75
17.0k
      fail(__FILE__, __LINE__,msg);
76
17.0k
   }
77
3.48M
   ++mPosition;
78
3.48M
   return CurrentPosition(*this);
79
3.48M
}
80
81
ParseBuffer::CurrentPosition
82
ParseBuffer::skipChars(const char* cs)
83
6.35k
{
84
6.35k
   const char* match = cs;
85
12.7k
   while (*match != 0)
86
6.37k
   {
87
6.37k
      if (eof() || (*match != *mPosition))
88
6.35k
      {
89
6.35k
          Data msg("Expected \"");
90
6.35k
          msg += cs;
91
6.35k
          msg +=  "\"";
92
6.35k
         fail(__FILE__, __LINE__,msg);
93
6.35k
      }
94
6.37k
      match++;
95
6.37k
      mPosition++;
96
6.37k
   }
97
6.35k
   return CurrentPosition(*this);
98
6.35k
}
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
9.22k
{
122
9.22k
   assertNotEof();
123
54.7M
   while (mPosition < mEnd)
124
54.7M
   {
125
54.7M
      switch (*mPosition)
126
54.7M
      {
127
931
         case ' ' :
128
1.19k
         case '\t' : 
129
1.87k
         case '\r' : 
130
4.67k
         case '\n' : 
131
4.67k
            return CurrentPosition(*this);
132
54.7M
         default : 
133
54.7M
            mPosition++;
134
54.7M
      }
135
54.7M
   }
136
4.55k
   return CurrentPosition(*this);
137
9.22k
}
138
139
ParseBuffer::CurrentPosition
140
ParseBuffer::skipWhitespace()
141
12.0M
{
142
12.0M
   while (mPosition < mEnd)
143
12.0M
   {
144
12.0M
      switch (*mPosition)
145
12.0M
      {
146
7.24k
         case ' ' :
147
11.9k
         case '\t' : 
148
20.2k
         case '\r' : 
149
42.4k
         case '\n' : 
150
42.4k
         {
151
42.4k
            mPosition++;
152
42.4k
            break;
153
20.2k
         }
154
12.0M
         default : 
155
12.0M
            return CurrentPosition(*this);
156
12.0M
      }
157
12.0M
   }
158
21.6k
   return CurrentPosition(*this);
159
12.0M
}
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
6.55k
{
250
6.55k
   resip_assert(cs);
251
6.55k
   unsigned int l = (unsigned int)strlen(cs);
252
253
6.55k
   const char* rpos;
254
6.55k
   const char* cpos;
255
   // Checking mPosition >= mEnd - l +1 is unnecessary because there won't be
256
   // enough bytes left to find [cs].
257
54.1M
   while (mPosition < mEnd - l + 1)
258
54.1M
   {
259
54.1M
      rpos = mPosition;
260
54.1M
      cpos = cs;
261
54.1M
      for (unsigned int i = 0; i < l; i++)
262
54.1M
      {
263
54.1M
         if (*cpos++ != *rpos++)
264
54.0M
         {
265
54.0M
            mPosition++;
266
54.0M
            goto skip;
267
54.0M
         }
268
54.1M
      }
269
4.51k
      return CurrentPosition(*this);
270
54.0M
     skip: ;
271
54.0M
   }
272
   // Advance to the end since we didn't find a match.
273
2.04k
   mPosition = mEnd;
274
2.04k
   return CurrentPosition(*this);
275
6.55k
}
276
277
ParseBuffer::CurrentPosition
278
ParseBuffer::skipToChars(const Data& sub)
279
6.48k
{
280
6.48k
   const char* begSub = sub.mBuf;
281
6.48k
   const char* endSub = sub.mBuf + sub.mSize;
282
6.48k
   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
6.48k
   while (true)
289
6.48k
   {
290
101M
next:
291
101M
     const char* searchPos = mPosition;
292
101M
     const char* subPos = sub.mBuf;
293
294
101M
     while (subPos != endSub) 
295
101M
     {
296
101M
         if (searchPos == mEnd)
297
6.36k
         {
298
            // nope
299
6.36k
            mPosition = mEnd;
300
6.36k
            return CurrentPosition(*this);
301
6.36k
         }
302
101M
         if (*subPos++ != *searchPos++)
303
101M
         {
304
            // nope, but try the next position
305
101M
            ++mPosition;
306
101M
            goto next;
307
101M
         }
308
101M
     }
309
     // found a match
310
115
     return CurrentPosition(*this);
311
101M
   }
312
6.48k
}
313
314
bool 
315
ParseBuffer::oneOf(char c, const char* cs)
316
418M
{
317
1.32G
   while (*cs)
318
905M
   {
319
905M
      if (c == *(cs++))
320
1.48M
      {
321
1.48M
         return true;
322
1.48M
      }
323
905M
   }
324
417M
   return false;
325
418M
}
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
33.6k
{
343
94.3M
   while (mPosition < mEnd)
344
94.3M
   {
345
94.3M
      if (oneOf(*mPosition, cs))
346
24.4k
      {
347
24.4k
         return CurrentPosition(*this);
348
24.4k
      }
349
94.3M
      else
350
94.3M
      {
351
94.3M
         mPosition++;
352
94.3M
      }
353
94.3M
   }
354
9.19k
   return CurrentPosition(*this);
355
33.6k
}
356
357
ParseBuffer::CurrentPosition
358
ParseBuffer::skipToOneOf(const char* cs1,
359
                         const char* cs2)
360
1.46M
{
361
162M
   while (mPosition < mEnd)
362
162M
   {
363
162M
      if (oneOf(*mPosition, cs1) ||
364
161M
          oneOf(*mPosition, cs2))
365
1.45M
      {
366
1.45M
         return CurrentPosition(*this);
367
1.45M
      }
368
161M
      else
369
161M
      {
370
161M
         mPosition++;
371
161M
      }
372
162M
   }
373
10.2k
   return CurrentPosition(*this);
374
1.46M
}
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
3.40k
{
415
15.4M
   while (mPosition < mEnd)
416
15.4M
   {
417
      // !dlb! mark character encoding
418
15.4M
      if (*mPosition == '\\')
419
2.62k
      {
420
2.62k
         mPosition += 2;
421
2.62k
      }
422
15.4M
      else if (*mPosition == quote)
423
2.84k
      {
424
2.84k
         return mPosition;
425
2.84k
      }
426
15.4M
      else
427
15.4M
      {
428
15.4M
         mPosition++;
429
15.4M
      }
430
15.4M
   }
431
432
566
   {
433
566
      Data msg("Missing '");
434
566
      msg += quote;
435
566
      msg += "'";
436
566
      fail(__FILE__,__LINE__,msg);
437
566
   }
438
566
   return 0;
439
3.40k
}
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
253
{
455
1.03k
   while (!bof())
456
1.03k
   {
457
1.03k
      switch (*(--mPosition))
458
1.03k
      {
459
198
         case ' ' :
460
393
         case '\t' : 
461
588
         case '\r' : 
462
785
         case '\n' : 
463
785
         {
464
785
            break;
465
588
         }
466
253
         default : 
467
253
            return ++mPosition;
468
1.03k
      }
469
1.03k
   }
470
0
   return mBuff;
471
253
}
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
4
{
506
38
   while (!bof())
507
38
   {
508
38
      if (*(--mPosition) == c)
509
4
      {
510
4
         return ++mPosition;
511
4
      }
512
38
   }
513
0
   return mBuff;
514
4
}
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
2.06M
{
532
2.06M
   if (!(mBuff <= start && start <= mPosition))
533
0
   {
534
0
      fail(__FILE__, __LINE__,"Bad anchor position");
535
0
   }
536
537
2.06M
   if (data.mShareEnum == Data::Take)
538
0
   {
539
0
      delete[] data.mBuf;
540
0
   }
541
2.06M
   data.mSize = (unsigned int)(mPosition - start);
542
2.06M
   data.mBuf = const_cast<char*>(start);
543
2.06M
   data.mCapacity = data.mSize;
544
2.06M
   data.mShareEnum = Data::Share;
545
2.06M
}
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
954
{
571
954
   if (!(mBuff <= start && start <= mPosition))
572
0
   {
573
0
      fail(__FILE__, __LINE__, "Bad anchor position");
574
0
   }
575
576
954
   {
577
954
      const char* current = start;   
578
5.65M
      while (current < mPosition)
579
5.65M
      {
580
5.65M
         if (*current == '%')
581
457
         {
582
            // needs to be unencoded
583
457
            goto copy;
584
457
         }
585
5.65M
         current++;
586
5.65M
      }
587
      // can use an overlay
588
497
      data(dataToUse, start);
589
497
      return;
590
954
   }
591
592
457
  copy:
593
457
   if ((size_t)(mPosition-start) > dataToUse.mCapacity)
594
242
   {
595
242
      dataToUse.resize((Data::size_type)(mPosition-start), false);
596
242
   }
597
598
457
   char* target = dataToUse.mBuf;
599
457
   const char* current = start;   
600
4.45M
   while (current < mPosition)
601
4.45M
   {
602
4.45M
      if (*current == '%')
603
1.99k
      {
604
1.99k
         current++;
605
1.99k
         if (mPosition - current < 2)
606
66
         {
607
66
            fail(__FILE__, __LINE__,"Illegal escaping");
608
66
         }
609
1.99k
         const char high = hexToByte[(unsigned char)*current];
610
1.99k
         const char low = hexToByte[(unsigned char)*(current + 1)];
611
1.99k
         if (high!='k' && low!='k')
612
1.73k
         {
613
1.73k
            unsigned char escaped = 0;            
614
1.73k
            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
1.73k
            if (escaped > 31 && escaped != 127 && escaped != 58)
622
437
            {
623
437
               *target++ = escaped;
624
437
               current+= 2;
625
437
            }
626
1.29k
            else
627
1.29k
            {
628
1.29k
               *target++ = '%';
629
1.29k
               *target++ = *current++;
630
1.29k
               *target++ = *current++;
631
1.29k
            }
632
1.73k
         }
633
261
         else
634
261
         {
635
261
            fail(__FILE__, __LINE__,"Illegal escaping, not hex");
636
261
         }
637
1.99k
      }
638
4.45M
      else
639
4.45M
      {
640
4.45M
         *target++ = *current++;
641
4.45M
      }
642
4.45M
   }
643
457
   *target = 0;
644
457
   dataToUse.mSize = (Data::size_type)(target - dataToUse.mBuf);
645
457
}
646
647
Data
648
ParseBuffer::data(const char* start) const
649
1.36M
{
650
1.36M
   if (!(mBuff <= start && start <= mPosition))
651
0
   {
652
      
653
0
      fail(__FILE__, __LINE__,"Bad anchor position");
654
0
   }
655
656
1.36M
   Data data(start, (Data::size_type)(mPosition - start));
657
1.36M
   return data;
658
1.36M
}
659
660
int
661
ParseBuffer::integer()
662
55.3k
{
663
55.3k
   if (this->eof())
664
507
   {
665
507
      fail(__FILE__, __LINE__,"Expected a digit, got eof ");
666
507
   }
667
668
55.3k
   bool negative = false;
669
55.3k
   if (*mPosition == '-')
670
819
   {
671
819
      negative = true;
672
819
      ++mPosition;
673
819
      assertNotEof();
674
819
   }
675
54.5k
   else if (*mPosition == '+')
676
213
   {
677
213
      ++mPosition;
678
213
      assertNotEof();
679
213
   }
680
681
55.3k
   if (!isdigit(static_cast< unsigned char >(*mPosition)))
682
11.8k
   {
683
11.8k
      Data msg("Expected a digit, got: ");
684
11.8k
      msg += Data(mPosition, (Data::size_type)(mEnd - mPosition));
685
11.8k
      fail(__FILE__, __LINE__,msg);
686
11.8k
   }
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
55.3k
   const unsigned int absoluteLimit = negative ? -(unsigned int)INT_MIN : INT_MAX;
694
   // maximum value for full number except last digit
695
55.3k
   const unsigned int border = absoluteLimit / 10;
696
   // value the last digit must not exceed
697
55.3k
   const unsigned int digitLimit = absoluteLimit % 10;
698
699
55.3k
   unsigned int num = 0;
700
176k
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
701
121k
   {
702
121k
      const unsigned int c = *mPosition++ - '0';
703
121k
      if (num > border || (num == border && c > digitLimit)) {
704
128
         fail(__FILE__, __LINE__,"Overflow detected.");
705
128
      }
706
121k
      num *= 10;
707
121k
      num += c;
708
121k
    }
709
55.3k
    if (negative)
710
771
    {
711
771
        num = -num;
712
771
    }
713
55.3k
    return num;
714
#ifdef _MSC_VER
715
#pragma warning( pop ) 
716
#endif
717
55.3k
}
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
25.4k
{
748
25.4k
   const char* begin=mPosition;
749
25.4k
   uint32_t num = 0;
750
55.6k
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
751
30.1k
   {
752
30.1k
      num = num*10 + (*mPosition-'0');
753
30.1k
      ++mPosition;
754
30.1k
   }
755
756
25.4k
   switch(mPosition-begin)
757
25.4k
   {
758
18.7k
      case 0:
759
18.7k
         fail(__FILE__, __LINE__,"Expected a digit");
760
22.3k
      case 1:
761
22.6k
      case 2:
762
22.8k
      case 3:
763
23.0k
      case 4:
764
23.2k
      case 5:
765
23.5k
      case 6:
766
23.7k
      case 7:
767
23.9k
      case 8:
768
24.1k
      case 9:
769
24.1k
         break;
770
1.03k
      case 10:
771
1.03k
         if(*begin<'4')
772
312
         {
773
312
            break;
774
312
         }
775
719
         else if(*begin=='4' && num >= 4000000000UL)
776
258
         {
777
258
            break;
778
258
         }
779
700
      default:
780
700
         fail(__FILE__, __LINE__,"Overflow detected");
781
25.4k
   }
782
783
5.99k
   return num;
784
25.4k
}
785
786
uint64_t
787
ParseBuffer::uInt64()
788
3.86k
{
789
3.86k
   const char* begin=mPosition;
790
3.86k
   uint64_t num = 0;
791
5.95k
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
792
2.09k
   {
793
2.09k
      num = num*10 + (*mPosition-'0');
794
2.09k
      ++mPosition;
795
2.09k
   }
796
797
3.86k
   switch(mPosition-begin)
798
3.86k
   {
799
3.72k
      case 0:
800
3.72k
         fail(__FILE__, __LINE__,"Expected a digit");
801
3.73k
      case 1:
802
3.74k
      case 2:
803
3.74k
      case 3:
804
3.74k
      case 4:
805
3.75k
      case 5:
806
3.75k
      case 6:
807
3.75k
      case 7:
808
3.76k
      case 8:
809
3.76k
      case 9:
810
3.76k
      case 10:
811
3.77k
      case 11:
812
3.77k
      case 12:
813
3.77k
      case 13:
814
3.77k
      case 14:
815
3.78k
      case 15:
816
3.78k
      case 16:
817
3.78k
      case 17:
818
3.79k
      case 18:
819
3.79k
      case 19:
820
3.79k
         break;
821
64
      case 20:
822
64
         if(*begin=='1' && num >= 10000000000000000000ULL)
823
36
         {
824
36
            break;
825
36
         }
826
33
      default:
827
33
         fail(__FILE__, __LINE__,"Overflow detected");
828
3.86k
   }
829
830
104
   return num;
831
3.86k
}
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
3.49k
{
869
   // parse a qvalue into an integer between 0 and 1000  (ex: 1.0 -> 1000,  0.8 -> 800, 0.05 -> 50)
870
3.49k
   const char* s = mPosition;
871
3.49k
   try
872
3.49k
   {
873
3.49k
      int num = integer();
874
3.49k
      if (num == 1)
875
1.19k
      {
876
1.19k
         num = 1000;
877
1.19k
      }
878
2.30k
      else if (num != 0)
879
900
      {
880
         // error: qvalue must start with 1 or 0
881
900
         return 0;
882
900
      }
883
      
884
2.59k
      if (!eof() && *mPosition == '.')
885
1.20k
      {
886
1.20k
         skipChar();
887
         
888
1.20k
         int i = 100;
889
2.81k
         while(!eof() && isdigit(static_cast< unsigned char >(*mPosition)) && i)
890
1.60k
         {
891
1.60k
            num += (*mPosition-'0') * i;
892
1.60k
            i /= 10;
893
1.60k
            skipChar();
894
1.60k
         }
895
1.20k
      }
896
2.59k
      return num;
897
3.49k
   }
898
3.49k
   catch (ParseException&)
899
3.49k
   {
900
232
      Data msg("Expected a floating point value, got: ");
901
232
      msg += Data(s, (Data::size_type)(mPosition - s));
902
232
      fail(__FILE__, __LINE__,msg);
903
232
      return 0;
904
232
   }
905
3.49k
}
906
   
907
908
Data
909
spaces(unsigned int numSpaces)
910
75.8k
{
911
75.8k
   Data sps(numSpaces, Data::Preallocate);
912
191M
   for (unsigned int i = 0; i < numSpaces; i++)
913
190M
   {
914
190M
      sps += ' ';
915
190M
   }
916
75.8k
   return sps;
917
75.8k
}
918
919
Data 
920
escapeAndAnnotate(const char* buffer, 
921
                  Data::size_type size,
922
                  const char* position)
923
82.2k
{ 
924
82.2k
   Data ret(2*size+16, Data::Preallocate);
925
926
82.2k
   const char* lastReturn = buffer;
927
82.2k
   int lineCount = 0;
928
82.2k
   bool doneAt = false;
929
930
82.2k
   const char* p = buffer;
931
1.17G
   for (unsigned int i = 0; i < size; i++)
932
1.17G
   {
933
1.17G
      unsigned char c = *p++;
934
935
1.17G
      switch (c)
936
1.17G
      {
937
115k
         case 0x0D: // CR
938
115k
         {
939
115k
            continue;
940
0
         }
941
1.40M
         case 0x0A: // LF
942
1.40M
         {
943
1.40M
            if (!doneAt && p >= position)
944
30.1k
            {
945
30.1k
               ret += "[CRLF]\n";
946
30.1k
               ret += spaces((unsigned int)(position - lastReturn));
947
30.1k
               ret += "^[CRLF]\n";
948
30.1k
               doneAt = true;
949
30.1k
            }
950
1.37M
            else
951
1.37M
            {
952
1.37M
               lastReturn = p;
953
1.37M
               ret += c;
954
1.37M
            }
955
1.40M
            lineCount++;
956
1.40M
            continue;
957
0
         }
958
1.17G
      }
959
960
1.17G
      if (iscntrl(static_cast< unsigned char >(c)) || (c >= 0x7F))
961
376M
      {
962
376M
         ret +='*'; // indicates unprintable character
963
376M
         continue;
964
376M
      }
965
966
798M
      ret += c;
967
798M
   }
968
82.2k
   if (!doneAt && p >= position)
969
45.7k
   {
970
45.7k
      ret += "\n";
971
45.7k
      ret += spaces((unsigned int)(position - lastReturn));
972
45.7k
      ret += "^\n";
973
45.7k
   }
974
975
82.2k
   return ret;
976
82.2k
}
977
978
void
979
ParseBuffer::fail(const char* file, unsigned int line, const Data& detail) const
980
82.2k
{
981
82.2k
    Data errmsg;
982
82.2k
    {
983
82.2k
       DataStream ds(errmsg);
984
82.2k
       ds << file << ":" << line
985
82.2k
          << ", Parse failed ";
986
987
82.2k
       if (detail != Data::Empty) ds << detail << ' ' ;
988
989
82.2k
       ds << "in context: " << mErrorContext
990
82.2k
          << std::endl
991
82.2k
          << escapeAndAnnotate(mBuff, (Data::size_type)(mEnd - mBuff), mPosition);
992
          
993
82.2k
       ds.flush();
994
82.2k
   }
995
82.2k
   DebugLog(<<errmsg);
996
82.2k
   throw ParseException(errmsg, mErrorContext, file, line);
997
82.2k
}
998
999
ParseBuffer::Pointer::Pointer(const ParseBuffer& pb,
1000
                              const char* position,
1001
                              bool atEof)
1002
5.59k
   : mPb(pb),
1003
5.59k
     mPosition(position),
1004
5.59k
     mIsValid(!atEof)
1005
5.59k
{}
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
 */