Coverage Report

Created: 2026-01-09 06:37

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
150k
   : mBuff(buff),
22
150k
     mPosition(buff),
23
150k
     mEnd(buff+len),
24
150k
     mErrorContext(errorContext)
25
150k
{}
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
654
   : mBuff(data.data()),
38
654
     mPosition(mBuff),
39
654
     mEnd(mBuff + data.size()),
40
654
     mErrorContext(errorContext)
41
654
{}
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
2.73M
{
66
2.73M
   if (eof())
67
2.88k
   {
68
2.88k
      fail(__FILE__, __LINE__,"skipped over eof");
69
2.88k
   }
70
2.73M
   if (*mPosition != c)
71
16.5k
   {
72
16.5k
      Data msg("expected '");
73
16.5k
      msg += c;
74
16.5k
      msg += "'";
75
16.5k
      fail(__FILE__, __LINE__,msg);
76
16.5k
   }
77
2.73M
   ++mPosition;
78
2.73M
   return CurrentPosition(*this);
79
2.73M
}
80
81
ParseBuffer::CurrentPosition
82
ParseBuffer::skipChars(const char* cs)
83
6.11k
{
84
6.11k
   const char* match = cs;
85
12.2k
   while (*match != 0)
86
6.13k
   {
87
6.13k
      if (eof() || (*match != *mPosition))
88
6.11k
      {
89
6.11k
          Data msg("Expected \"");
90
6.11k
          msg += cs;
91
6.11k
          msg +=  "\"";
92
6.11k
         fail(__FILE__, __LINE__,msg);
93
6.11k
      }
94
6.13k
      match++;
95
6.13k
      mPosition++;
96
6.13k
   }
97
6.11k
   return CurrentPosition(*this);
98
6.11k
}
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
8.88k
{
122
8.88k
   assertNotEof();
123
55.4M
   while (mPosition < mEnd)
124
55.4M
   {
125
55.4M
      switch (*mPosition)
126
55.4M
      {
127
912
         case ' ' :
128
1.18k
         case '\t' : 
129
1.84k
         case '\r' : 
130
4.54k
         case '\n' : 
131
4.54k
            return CurrentPosition(*this);
132
55.4M
         default : 
133
55.4M
            mPosition++;
134
55.4M
      }
135
55.4M
   }
136
4.33k
   return CurrentPosition(*this);
137
8.88k
}
138
139
ParseBuffer::CurrentPosition
140
ParseBuffer::skipWhitespace()
141
7.24M
{
142
7.28M
   while (mPosition < mEnd)
143
7.26M
   {
144
7.26M
      switch (*mPosition)
145
7.26M
      {
146
7.42k
         case ' ' :
147
12.2k
         case '\t' : 
148
20.2k
         case '\r' : 
149
41.9k
         case '\n' : 
150
41.9k
         {
151
41.9k
            mPosition++;
152
41.9k
            break;
153
20.2k
         }
154
7.22M
         default : 
155
7.22M
            return CurrentPosition(*this);
156
7.26M
      }
157
7.26M
   }
158
20.4k
   return CurrentPosition(*this);
159
7.24M
}
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.31k
{
250
6.31k
   resip_assert(cs);
251
6.31k
   unsigned int l = (unsigned int)strlen(cs);
252
253
6.31k
   const char* rpos;
254
6.31k
   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.6M
   while (mPosition < mEnd - l + 1)
258
54.6M
   {
259
54.6M
      rpos = mPosition;
260
54.6M
      cpos = cs;
261
54.6M
      for (unsigned int i = 0; i < l; i++)
262
54.6M
      {
263
54.6M
         if (*cpos++ != *rpos++)
264
54.6M
         {
265
54.6M
            mPosition++;
266
54.6M
            goto skip;
267
54.6M
         }
268
54.6M
      }
269
4.40k
      return CurrentPosition(*this);
270
54.6M
     skip: ;
271
54.6M
   }
272
   // Advance to the end since we didn't find a match.
273
1.90k
   mPosition = mEnd;
274
1.90k
   return CurrentPosition(*this);
275
6.31k
}
276
277
ParseBuffer::CurrentPosition
278
ParseBuffer::skipToChars(const Data& sub)
279
6.24k
{
280
6.24k
   const char* begSub = sub.mBuf;
281
6.24k
   const char* endSub = sub.mBuf + sub.mSize;
282
6.24k
   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.24k
   while (true)
289
6.24k
   {
290
111M
next:
291
111M
     const char* searchPos = mPosition;
292
111M
     const char* subPos = sub.mBuf;
293
294
111M
     while (subPos != endSub) 
295
111M
     {
296
111M
         if (searchPos == mEnd)
297
6.12k
         {
298
            // nope
299
6.12k
            mPosition = mEnd;
300
6.12k
            return CurrentPosition(*this);
301
6.12k
         }
302
111M
         if (*subPos++ != *searchPos++)
303
111M
         {
304
            // nope, but try the next position
305
111M
            ++mPosition;
306
111M
            goto next;
307
111M
         }
308
111M
     }
309
     // found a match
310
117
     return CurrentPosition(*this);
311
111M
   }
312
6.24k
}
313
314
bool 
315
ParseBuffer::oneOf(char c, const char* cs)
316
452M
{
317
1.40G
   while (*cs)
318
957M
   {
319
957M
      if (c == *(cs++))
320
732k
      {
321
732k
         return true;
322
732k
      }
323
957M
   }
324
451M
   return false;
325
452M
}
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.2k
{
343
112M
   while (mPosition < mEnd)
344
112M
   {
345
112M
      if (oneOf(*mPosition, cs))
346
24.5k
      {
347
24.5k
         return CurrentPosition(*this);
348
24.5k
      }
349
112M
      else
350
112M
      {
351
112M
         mPosition++;
352
112M
      }
353
112M
   }
354
8.74k
   return CurrentPosition(*this);
355
33.2k
}
356
357
ParseBuffer::CurrentPosition
358
ParseBuffer::skipToOneOf(const char* cs1,
359
                         const char* cs2)
360
718k
{
361
170M
   while (mPosition < mEnd)
362
170M
   {
363
170M
      if (oneOf(*mPosition, cs1) ||
364
169M
          oneOf(*mPosition, cs2))
365
708k
      {
366
708k
         return CurrentPosition(*this);
367
708k
      }
368
169M
      else
369
169M
      {
370
169M
         mPosition++;
371
169M
      }
372
170M
   }
373
9.87k
   return CurrentPosition(*this);
374
718k
}
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.32k
{
415
15.5M
   while (mPosition < mEnd)
416
15.4M
   {
417
      // !dlb! mark character encoding
418
15.4M
      if (*mPosition == '\\')
419
2.77k
      {
420
2.77k
         mPosition += 2;
421
2.77k
      }
422
15.4M
      else if (*mPosition == quote)
423
2.76k
      {
424
2.76k
         return mPosition;
425
2.76k
      }
426
15.4M
      else
427
15.4M
      {
428
15.4M
         mPosition++;
429
15.4M
      }
430
15.4M
   }
431
432
556
   {
433
556
      Data msg("Missing '");
434
556
      msg += quote;
435
556
      msg += "'";
436
556
      fail(__FILE__,__LINE__,msg);
437
556
   }
438
556
   return 0;
439
3.32k
}
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
262
{
455
1.05k
   while (!bof())
456
1.05k
   {
457
1.05k
      switch (*(--mPosition))
458
1.05k
      {
459
203
         case ' ' :
460
398
         case '\t' : 
461
596
         case '\r' : 
462
795
         case '\n' : 
463
795
         {
464
795
            break;
465
596
         }
466
262
         default : 
467
262
            return ++mPosition;
468
1.05k
      }
469
1.05k
   }
470
0
   return mBuff;
471
262
}
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.03M
{
532
2.03M
   if (!(mBuff <= start && start <= mPosition))
533
0
   {
534
0
      fail(__FILE__, __LINE__,"Bad anchor position");
535
0
   }
536
537
2.03M
   if (data.mShareEnum == Data::Take)
538
0
   {
539
0
      delete[] data.mBuf;
540
0
   }
541
2.03M
   data.mSize = (unsigned int)(mPosition - start);
542
2.03M
   data.mBuf = const_cast<char*>(start);
543
2.03M
   data.mCapacity = data.mSize;
544
2.03M
   data.mShareEnum = Data::Share;
545
2.03M
}
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
911
{
571
911
   if (!(mBuff <= start && start <= mPosition))
572
0
   {
573
0
      fail(__FILE__, __LINE__, "Bad anchor position");
574
0
   }
575
576
911
   {
577
911
      const char* current = start;   
578
3.68M
      while (current < mPosition)
579
3.68M
      {
580
3.68M
         if (*current == '%')
581
457
         {
582
            // needs to be unencoded
583
457
            goto copy;
584
457
         }
585
3.68M
         current++;
586
3.68M
      }
587
      // can use an overlay
588
454
      data(dataToUse, start);
589
454
      return;
590
911
   }
591
592
457
  copy:
593
457
   if ((size_t)(mPosition-start) > dataToUse.mCapacity)
594
244
   {
595
244
      dataToUse.resize((Data::size_type)(mPosition-start), false);
596
244
   }
597
598
457
   char* target = dataToUse.mBuf;
599
457
   const char* current = start;   
600
4.86M
   while (current < mPosition)
601
4.86M
   {
602
4.86M
      if (*current == '%')
603
1.91k
      {
604
1.91k
         current++;
605
1.91k
         if (mPosition - current < 2)
606
63
         {
607
63
            fail(__FILE__, __LINE__,"Illegal escaping");
608
63
         }
609
1.91k
         const char high = hexToByte[(unsigned char)*current];
610
1.91k
         const char low = hexToByte[(unsigned char)*(current + 1)];
611
1.91k
         if (high!='k' && low!='k')
612
1.65k
         {
613
1.65k
            unsigned char escaped = 0;            
614
1.65k
            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.65k
            if (escaped > 31 && escaped != 127 && escaped != 58)
622
461
            {
623
461
               *target++ = escaped;
624
461
               current+= 2;
625
461
            }
626
1.19k
            else
627
1.19k
            {
628
1.19k
               *target++ = '%';
629
1.19k
               *target++ = *current++;
630
1.19k
               *target++ = *current++;
631
1.19k
            }
632
1.65k
         }
633
259
         else
634
259
         {
635
259
            fail(__FILE__, __LINE__,"Illegal escaping, not hex");
636
259
         }
637
1.91k
      }
638
4.85M
      else
639
4.85M
      {
640
4.85M
         *target++ = *current++;
641
4.85M
      }
642
4.86M
   }
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
610k
{
650
610k
   if (!(mBuff <= start && start <= mPosition))
651
0
   {
652
      
653
0
      fail(__FILE__, __LINE__,"Bad anchor position");
654
0
   }
655
656
610k
   Data data(start, (Data::size_type)(mPosition - start));
657
610k
   return data;
658
610k
}
659
660
int
661
ParseBuffer::integer()
662
43.9k
{
663
43.9k
   if (this->eof())
664
480
   {
665
480
      fail(__FILE__, __LINE__,"Expected a digit, got eof ");
666
480
   }
667
668
43.9k
   bool negative = false;
669
43.9k
   if (*mPosition == '-')
670
784
   {
671
784
      negative = true;
672
784
      ++mPosition;
673
784
      assertNotEof();
674
784
   }
675
43.1k
   else if (*mPosition == '+')
676
224
   {
677
224
      ++mPosition;
678
224
      assertNotEof();
679
224
   }
680
681
43.9k
   if (!isdigit(static_cast< unsigned char >(*mPosition)))
682
11.4k
   {
683
11.4k
      Data msg("Expected a digit, got: ");
684
11.4k
      msg += Data(mPosition, (Data::size_type)(mEnd - mPosition));
685
11.4k
      fail(__FILE__, __LINE__,msg);
686
11.4k
   }
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
43.9k
   const unsigned int absoluteLimit = negative ? -(unsigned int)INT_MIN : INT_MAX;
694
   // maximum value for full number except last digit
695
43.9k
   const unsigned int border = absoluteLimit / 10;
696
   // value the last digit must not exceed
697
43.9k
   const unsigned int digitLimit = absoluteLimit % 10;
698
699
43.9k
   unsigned int num = 0;
700
172k
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
701
128k
   {
702
128k
      const unsigned int c = *mPosition++ - '0';
703
128k
      if (num > border || (num == border && c > digitLimit)) {
704
130
         fail(__FILE__, __LINE__,"Overflow detected.");
705
130
      }
706
128k
      num *= 10;
707
128k
      num += c;
708
128k
    }
709
43.9k
    if (negative)
710
736
    {
711
736
        num = -num;
712
736
    }
713
43.9k
    return num;
714
#ifdef _MSC_VER
715
#pragma warning( pop ) 
716
#endif
717
43.9k
}
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
58.8k
{
748
58.8k
   const char* begin=mPosition;
749
58.8k
   uint32_t num = 0;
750
123k
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
751
64.4k
   {
752
64.4k
      num = num*10 + (*mPosition-'0');
753
64.4k
      ++mPosition;
754
64.4k
   }
755
756
58.8k
   switch(mPosition-begin)
757
58.8k
   {
758
18.3k
      case 0:
759
18.3k
         fail(__FILE__, __LINE__,"Expected a digit");
760
55.4k
      case 1:
761
56.0k
      case 2:
762
56.2k
      case 3:
763
56.5k
      case 4:
764
56.7k
      case 5:
765
56.9k
      case 6:
766
57.2k
      case 7:
767
57.4k
      case 8:
768
57.6k
      case 9:
769
57.6k
         break;
770
1.01k
      case 10:
771
1.01k
         if(*begin<'4')
772
291
         {
773
291
            break;
774
291
         }
775
719
         else if(*begin=='4' && num >= 4000000000UL)
776
275
         {
777
275
            break;
778
275
         }
779
681
      default:
780
681
         fail(__FILE__, __LINE__,"Overflow detected");
781
58.8k
   }
782
783
39.8k
   return num;
784
58.8k
}
785
786
uint64_t
787
ParseBuffer::uInt64()
788
3.80k
{
789
3.80k
   const char* begin=mPosition;
790
3.80k
   uint64_t num = 0;
791
11.2k
   while (!eof() && isdigit(static_cast< unsigned char >(*mPosition)))
792
7.43k
   {
793
7.43k
      num = num*10 + (*mPosition-'0');
794
7.43k
      ++mPosition;
795
7.43k
   }
796
797
3.80k
   switch(mPosition-begin)
798
3.80k
   {
799
3.66k
      case 0:
800
3.66k
         fail(__FILE__, __LINE__,"Expected a digit");
801
3.67k
      case 1:
802
3.68k
      case 2:
803
3.68k
      case 3:
804
3.69k
      case 4:
805
3.69k
      case 5:
806
3.69k
      case 6:
807
3.69k
      case 7:
808
3.70k
      case 8:
809
3.70k
      case 9:
810
3.70k
      case 10:
811
3.71k
      case 11:
812
3.71k
      case 12:
813
3.71k
      case 13:
814
3.72k
      case 14:
815
3.72k
      case 15:
816
3.72k
      case 16:
817
3.72k
      case 17:
818
3.73k
      case 18:
819
3.73k
      case 19:
820
3.73k
         break;
821
60
      case 20:
822
60
         if(*begin=='1' && num >= 10000000000000000000ULL)
823
43
         {
824
43
            break;
825
43
         }
826
23
      default:
827
23
         fail(__FILE__, __LINE__,"Overflow detected");
828
3.80k
   }
829
830
111
   return num;
831
3.80k
}
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.39k
{
869
   // parse a qvalue into an integer between 0 and 1000  (ex: 1.0 -> 1000,  0.8 -> 800, 0.05 -> 50)
870
3.39k
   const char* s = mPosition;
871
3.39k
   try
872
3.39k
   {
873
3.39k
      int num = integer();
874
3.39k
      if (num == 1)
875
1.23k
      {
876
1.23k
         num = 1000;
877
1.23k
      }
878
2.16k
      else if (num != 0)
879
881
      {
880
         // error: qvalue must start with 1 or 0
881
881
         return 0;
882
881
      }
883
      
884
2.51k
      if (!eof() && *mPosition == '.')
885
1.14k
      {
886
1.14k
         skipChar();
887
         
888
1.14k
         int i = 100;
889
2.67k
         while(!eof() && isdigit(static_cast< unsigned char >(*mPosition)) && i)
890
1.52k
         {
891
1.52k
            num += (*mPosition-'0') * i;
892
1.52k
            i /= 10;
893
1.52k
            skipChar();
894
1.52k
         }
895
1.14k
      }
896
2.51k
      return num;
897
3.39k
   }
898
3.39k
   catch (ParseException&)
899
3.39k
   {
900
249
      Data msg("Expected a floating point value, got: ");
901
249
      msg += Data(s, (Data::size_type)(mPosition - s));
902
249
      fail(__FILE__, __LINE__,msg);
903
249
      return 0;
904
249
   }
905
3.39k
}
906
   
907
908
Data
909
spaces(unsigned int numSpaces)
910
73.4k
{
911
73.4k
   Data sps(numSpaces, Data::Preallocate);
912
191M
   for (unsigned int i = 0; i < numSpaces; i++)
913
191M
   {
914
191M
      sps += ' ';
915
191M
   }
916
73.4k
   return sps;
917
73.4k
}
918
919
Data 
920
escapeAndAnnotate(const char* buffer, 
921
                  Data::size_type size,
922
                  const char* position)
923
79.6k
{ 
924
79.6k
   Data ret(2*size+16, Data::Preallocate);
925
926
79.6k
   const char* lastReturn = buffer;
927
79.6k
   int lineCount = 0;
928
79.6k
   bool doneAt = false;
929
930
79.6k
   const char* p = buffer;
931
1.45G
   for (unsigned int i = 0; i < size; i++)
932
1.45G
   {
933
1.45G
      unsigned char c = *p++;
934
935
1.45G
      switch (c)
936
1.45G
      {
937
219k
         case 0x0D: // CR
938
219k
         {
939
219k
            continue;
940
0
         }
941
2.89M
         case 0x0A: // LF
942
2.89M
         {
943
2.89M
            if (!doneAt && p >= position)
944
29.4k
            {
945
29.4k
               ret += "[CRLF]\n";
946
29.4k
               ret += spaces((unsigned int)(position - lastReturn));
947
29.4k
               ret += "^[CRLF]\n";
948
29.4k
               doneAt = true;
949
29.4k
            }
950
2.86M
            else
951
2.86M
            {
952
2.86M
               lastReturn = p;
953
2.86M
               ret += c;
954
2.86M
            }
955
2.89M
            lineCount++;
956
2.89M
            continue;
957
0
         }
958
1.45G
      }
959
960
1.44G
      if (iscntrl(static_cast< unsigned char >(c)) || (c >= 0x7F))
961
480M
      {
962
480M
         ret +='*'; // indicates unprintable character
963
480M
         continue;
964
480M
      }
965
966
967M
      ret += c;
967
967M
   }
968
79.6k
   if (!doneAt && p >= position)
969
44.0k
   {
970
44.0k
      ret += "\n";
971
44.0k
      ret += spaces((unsigned int)(position - lastReturn));
972
44.0k
      ret += "^\n";
973
44.0k
   }
974
975
79.6k
   return ret;
976
79.6k
}
977
978
void
979
ParseBuffer::fail(const char* file, unsigned int line, const Data& detail) const
980
79.6k
{
981
79.6k
    Data errmsg;
982
79.6k
    {
983
79.6k
       DataStream ds(errmsg);
984
79.6k
       ds << file << ":" << line
985
79.6k
          << ", Parse failed ";
986
987
79.6k
       if (detail != Data::Empty) ds << detail << ' ' ;
988
989
79.6k
       ds << "in context: " << mErrorContext
990
79.6k
          << std::endl
991
79.6k
          << escapeAndAnnotate(mBuff, (Data::size_type)(mEnd - mBuff), mPosition);
992
          
993
79.6k
       ds.flush();
994
79.6k
   }
995
79.6k
   DebugLog(<<errmsg);
996
79.6k
   throw ParseException(errmsg, mErrorContext, file, line);
997
79.6k
}
998
999
ParseBuffer::Pointer::Pointer(const ParseBuffer& pb,
1000
                              const char* position,
1001
                              bool atEof)
1002
5.36k
   : mPb(pb),
1003
5.36k
     mPosition(position),
1004
5.36k
     mIsValid(!atEof)
1005
5.36k
{}
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
 */