Coverage Report

Created: 2024-04-23 06:04

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