~ubuntu-branches/ubuntu/saucy/resiprocate/saucy-proposed

« back to all changes in this revision

Viewing changes to resip/stack/MsgHeaderScanner.cxx

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2012-05-17 19:29:59 UTC
  • Revision ID: package-import@ubuntu.com-20120517192959-vv00m77isztdy64q
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if defined(HAVE_CONFIG_H)
 
2
#include "config.h"
 
3
#endif
 
4
 
 
5
#include <ctype.h>
 
6
#include <limits.h>
 
7
#include <stdio.h>
 
8
#include "resip/stack/HeaderTypes.hxx"
 
9
#include "resip/stack/SipMessage.hxx"
 
10
#include "resip/stack/MsgHeaderScanner.hxx"
 
11
#include "rutil/WinLeakCheck.hxx"
 
12
 
 
13
namespace resip 
 
14
{
 
15
 
 
16
///////////////////////////////////////////////////////////////////////////////
 
17
//   Any character could be used as the chunk terminating sentinel, as long as
 
18
//   it would otherwise be character category "other".  The null character
 
19
//   was chosen because it is unlikely to occur naturally -- but it's OK if it
 
20
//   does.
 
21
 
 
22
enum { chunkTermSentinelChar = '\0' };
 
23
 
 
24
enum CharCategoryEnum
 
25
{
 
26
   ccChunkTermSentinel,
 
27
   ccOther,
 
28
   ccFieldName,
 
29
   ccWhitespace,
 
30
   ccColon,
 
31
   ccDoubleQuotationMark,
 
32
   ccLeftAngleBracket,
 
33
   ccRightAngleBracket,
 
34
   ccBackslash,
 
35
   ccComma,
 
36
   ccCarriageReturn,
 
37
   ccLineFeed,
 
38
   numCharCategories
 
39
};
 
40
typedef char CharCategory;
 
41
 
 
42
char* 
 
43
MsgHeaderScanner::allocateBuffer(int size)
 
44
{
 
45
   return new char[size + MaxNumCharsChunkOverflow];
 
46
}
 
47
 
 
48
struct CharInfo
 
49
{
 
50
      CharCategory category;
 
51
      MsgHeaderScanner::TextPropBitMask textPropBitMask;
 
52
};
 
53
    
 
54
static CharInfo charInfoArray[UCHAR_MAX+1];
 
55
    
 
56
static inline int c2i(unsigned char c)
 
57
{
 
58
   return static_cast<int>(c); 
 
59
}
 
60
 
 
61
static void initCharInfoArray()
 
62
{
 
63
   for(unsigned int charIndex = 0; charIndex <= UCHAR_MAX; ++charIndex) 
 
64
   {
 
65
      charInfoArray[charIndex].category = ccOther;
 
66
      charInfoArray[charIndex].textPropBitMask = 0;
 
67
   }
 
68
 
 
69
   for(const char *charPtr = "abcdefghijklmnopqrstuvwxyz"
 
70
          "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.!%*_+`'~";
 
71
       *charPtr;
 
72
       ++charPtr)
 
73
   {
 
74
      charInfoArray[c2i(*charPtr)].category = ccFieldName;
 
75
   }
 
76
 
 
77
   charInfoArray[c2i(' ')].category  = ccWhitespace;
 
78
   charInfoArray[c2i('\t')].category = ccWhitespace;
 
79
   charInfoArray[c2i(':')].category  = ccColon;
 
80
   charInfoArray[c2i('"')].category  = ccDoubleQuotationMark;
 
81
   charInfoArray[c2i('<')].category  = ccLeftAngleBracket;
 
82
   charInfoArray[c2i('>')].category  = ccRightAngleBracket;
 
83
   charInfoArray[c2i('\\')].category  = ccBackslash;
 
84
   charInfoArray[c2i(',')].category  = ccComma;
 
85
   charInfoArray[c2i('\r')].category = ccCarriageReturn;
 
86
   charInfoArray[c2i('\n')].category = ccLineFeed;
 
87
   // Assert: "chunkTermSentinelChar"'s category is still the default "ccOther".
 
88
   charInfoArray[c2i(chunkTermSentinelChar)].category = ccChunkTermSentinel;
 
89
   // Init text property bit masks.
 
90
   charInfoArray[c2i('\r')].textPropBitMask =
 
91
      MsgHeaderScanner::tpbmContainsLineBreak;
 
92
   charInfoArray[c2i('\n')].textPropBitMask =
 
93
      MsgHeaderScanner::tpbmContainsLineBreak;
 
94
   charInfoArray[c2i(' ')].textPropBitMask =
 
95
      MsgHeaderScanner::tpbmContainsWhitespace;
 
96
   charInfoArray[c2i('\t')].textPropBitMask =
 
97
      MsgHeaderScanner::tpbmContainsWhitespace;
 
98
   charInfoArray[c2i('\\')].textPropBitMask =
 
99
      MsgHeaderScanner::tpbmContainsBackslash;
 
100
   charInfoArray[c2i('%')].textPropBitMask =
 
101
      MsgHeaderScanner::tpbmContainsPercent;
 
102
   charInfoArray[c2i(';')].textPropBitMask =
 
103
      MsgHeaderScanner::tpbmContainsSemicolon;
 
104
   charInfoArray[c2i('(')].textPropBitMask =
 
105
      MsgHeaderScanner::tpbmContainsParen;
 
106
   charInfoArray[c2i(')')].textPropBitMask =
 
107
      MsgHeaderScanner::tpbmContainsParen;
 
108
}
 
109
 
 
110
///////////////////////////////////////////////////////////////////////////////
 
111
//   States marked '1' scan normal values.  States marked 'N' scan multi-values.
 
112
 
 
113
enum StateEnum
 
114
{
 
115
   sMsgStart,
 
116
   sHalfLineBreakAtMsgStart,
 
117
   sScanStatusLine,
 
118
   sHalfLineBreakAfterStatusLine,
 
119
   sAfterLineBreakAfterStatusLine,
 
120
   sScanFieldName,
 
121
   sScanWhitespaceAfter1FieldName,
 
122
   sScanWhitespaceAfterNFieldName,
 
123
   sScanWhitespaceOr1Value,
 
124
   sScanWhitespaceOrNValue,
 
125
   sHalfLineBreakInWhitespaceBefore1Value,
 
126
   sHalfLineBreakInWhitespaceBeforeNValue,
 
127
   sAfterLineBreakInWhitespaceBefore1Value,
 
128
   sAfterLineBreakInWhitespaceBeforeNValue,
 
129
   sScan1Value,
 
130
   sScanNValue,
 
131
   sHalfLineBreakIn1Value,
 
132
   sHalfLineBreakInNValue,
 
133
   sAfterLineBreakIn1Value,
 
134
   sAfterLineBreakInNValue,
 
135
   sScanNValueInQuotes,
 
136
   sAfterEscCharInQuotesInNValue,
 
137
   sHalfLineBreakInQuotesInNValue,
 
138
   sAfterLineBreakInQuotesInNValue,
 
139
   sScanNValueInAngles,
 
140
   sHalfLineBreakInAnglesInNValue,
 
141
   sAfterLineBreakInAnglesInNValue,
 
142
   sHalfLineBreakAfterLineBreak,
 
143
   numStates
 
144
};
 
145
 
 
146
typedef char State;
 
147
 
 
148
// For each '1' state, the 'N' state is "deltaOfNStateFrom1State" larger.
 
149
enum { deltaOfNStateFrom1State = 1 };
 
150
 
 
151
/////
 
152
    
 
153
enum TransitionActionEnum {
 
154
   taNone,
 
155
   taTermStatusLine,       // The current character terminates the status
 
156
   //     line.
 
157
   taTermFieldName,        // The current character terminates a field name.
 
158
   //     If the field supports multi-values, shift
 
159
   //     the state machine into multi-value scanning.
 
160
   taBeyondEmptyValue,     // The current character terminates an empty value.
 
161
   //     Implies taStartText.
 
162
   taTermValueAfterLineBreak, 
 
163
   // The previous two characters are a linebreak
 
164
   //      terminating a value.  Implies taStartText.
 
165
   taTermValue,            // The current character terminates a value.
 
166
   taStartText,            // The current character starts a text unit.
 
167
   //     (The status line, a field name, or a value.)
 
168
   taEndHeader,            // The current character mEnds_ the header.
 
169
   taChunkTermSentinel,    // Either the current character terminates the
 
170
   //    current chunk or it is an ordinary character.
 
171
   taError                 // The input is erroneous.
 
172
};
 
173
typedef char TransitionAction;
 
174
 
 
175
 
 
176
struct TransitionInfo
 
177
{
 
178
      TransitionAction  action;
 
179
      State             nextState;
 
180
};
 
181
 
 
182
static TransitionInfo stateMachine[numStates][numCharCategories];
 
183
 
 
184
inline void specTransition(State state,
 
185
                           CharCategory charCategory,
 
186
                           TransitionAction action,
 
187
                           State nextState)
 
188
{
 
189
   stateMachine[c2i(state)][c2i(charCategory)].action = action;
 
190
   stateMachine[c2i(state)][c2i(charCategory)].nextState = nextState;
 
191
}
 
192
 
 
193
static void specDefaultTransition(State state,
 
194
                                  TransitionAction action,
 
195
                                  State nextState)
 
196
{
 
197
   for (int charCategory = 0;
 
198
        charCategory < numCharCategories;
 
199
        ++charCategory) 
 
200
   {
 
201
      specTransition(state, charCategory, action, nextState);
 
202
   }
 
203
   specTransition(state, ccCarriageReturn, taError, state);
 
204
   specTransition(state, ccLineFeed, taError, state);
 
205
   specTransition(state, ccChunkTermSentinel, taChunkTermSentinel, state);
 
206
}
 
207
 
 
208
static void specHalfLineBreakState(State halfLineBreakState,
 
209
                                   State  afterLineBreakState)
 
210
{
 
211
   specDefaultTransition(halfLineBreakState, taError, halfLineBreakState);
 
212
   specTransition(halfLineBreakState, ccLineFeed, taNone, afterLineBreakState);
 
213
}
 
214
 
 
215
 
 
216
//   Single-value (1) scanning and multi-value (N) scanning involves several nearly
 
217
//   identical states.
 
218
//   "stateDelta" is either 0 or "deltaOfNStateFrom1State".
 
219
 
 
220
static void specXValueStates(int  stateDelta)
 
221
{
 
222
   specDefaultTransition(sScanWhitespaceAfter1FieldName + stateDelta,
 
223
                         taError,
 
224
                         sScanWhitespaceAfter1FieldName + stateDelta);
 
225
   specTransition(sScanWhitespaceAfter1FieldName + stateDelta,
 
226
                  ccWhitespace,
 
227
                  taNone,
 
228
                  sScanWhitespaceAfter1FieldName + stateDelta);
 
229
   specTransition(sScanWhitespaceAfter1FieldName + stateDelta,
 
230
                  ccColon,
 
231
                  taNone,
 
232
                  sScanWhitespaceOr1Value + stateDelta);
 
233
   specDefaultTransition(sScanWhitespaceOr1Value + stateDelta,
 
234
                         taStartText,
 
235
                         sScan1Value + stateDelta);
 
236
   specTransition(sScanWhitespaceOr1Value + stateDelta,
 
237
                  ccWhitespace,
 
238
                  taNone,
 
239
                  sScanWhitespaceOr1Value + stateDelta);
 
240
   if (stateDelta == deltaOfNStateFrom1State)
 
241
   {
 
242
      specTransition(sScanWhitespaceOr1Value + stateDelta,
 
243
                     ccComma,
 
244
                     taError,
 
245
                     sScanWhitespaceOr1Value + stateDelta);
 
246
      specTransition(sScanWhitespaceOr1Value + stateDelta,
 
247
                     ccLeftAngleBracket,
 
248
                     taStartText,
 
249
                     sScanNValueInAngles);
 
250
      specTransition(sScanWhitespaceOr1Value + stateDelta,
 
251
                     ccDoubleQuotationMark,
 
252
                     taStartText,
 
253
                     sScanNValueInQuotes);
 
254
   }
 
255
   specTransition(sScanWhitespaceOr1Value + stateDelta,
 
256
                  ccCarriageReturn,
 
257
                  taNone,
 
258
                  sHalfLineBreakInWhitespaceBefore1Value + stateDelta);
 
259
   specHalfLineBreakState(sHalfLineBreakInWhitespaceBefore1Value + stateDelta,
 
260
                          sAfterLineBreakInWhitespaceBefore1Value + stateDelta);
 
261
   specDefaultTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
 
262
                         taError,
 
263
                         sAfterLineBreakInWhitespaceBefore1Value + stateDelta);
 
264
   specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
 
265
                  ccFieldName,
 
266
                  taBeyondEmptyValue,
 
267
                  sScanFieldName);
 
268
   specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
 
269
                  ccWhitespace,
 
270
                  taNone,
 
271
                  sScanWhitespaceOr1Value + stateDelta);
 
272
   specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
 
273
                  ccCarriageReturn,
 
274
                  taBeyondEmptyValue,
 
275
                  sHalfLineBreakAfterLineBreak);
 
276
   specDefaultTransition(sScan1Value + stateDelta,
 
277
                         taNone,
 
278
                         sScan1Value + stateDelta);
 
279
   if (stateDelta == deltaOfNStateFrom1State)
 
280
   {
 
281
      specTransition(sScan1Value + stateDelta,
 
282
                     ccComma,
 
283
                     taTermValue,
 
284
                     sScanWhitespaceOr1Value + stateDelta);
 
285
      specTransition(sScan1Value + stateDelta,
 
286
                     ccLeftAngleBracket,
 
287
                     taNone,
 
288
                     sScanNValueInAngles);
 
289
      specTransition(sScan1Value + stateDelta,
 
290
                     ccDoubleQuotationMark,
 
291
                     taNone,
 
292
                     sScanNValueInQuotes);
 
293
   }
 
294
   specTransition(sScan1Value + stateDelta,
 
295
                  ccCarriageReturn,
 
296
                  taNone,
 
297
                  sHalfLineBreakIn1Value + stateDelta);
 
298
   specHalfLineBreakState(sHalfLineBreakIn1Value + stateDelta,
 
299
                          sAfterLineBreakIn1Value + stateDelta);
 
300
   specDefaultTransition(sAfterLineBreakIn1Value + stateDelta,
 
301
                         taError,
 
302
                         sAfterLineBreakIn1Value + stateDelta);
 
303
   specTransition(sAfterLineBreakIn1Value + stateDelta,
 
304
                  ccFieldName,
 
305
                  taTermValueAfterLineBreak,
 
306
                  sScanFieldName);
 
307
   specTransition(sAfterLineBreakIn1Value + stateDelta,
 
308
                  ccWhitespace,
 
309
                  taNone,
 
310
                  sScan1Value + stateDelta);
 
311
   specTransition(sAfterLineBreakIn1Value + stateDelta,
 
312
                  ccCarriageReturn,
 
313
                  taTermValueAfterLineBreak,
 
314
                  sHalfLineBreakAfterLineBreak);
 
315
}
 
316
 
 
317
static void initStateMachine()
 
318
{
 
319
   // By convention, error transitions maintain the same state.
 
320
   specDefaultTransition(sMsgStart, taStartText, sScanStatusLine);
 
321
   specTransition(sMsgStart,
 
322
                  ccCarriageReturn,
 
323
                  taNone,
 
324
                  sHalfLineBreakAtMsgStart);
 
325
   specTransition(sMsgStart, ccLineFeed, taError, sMsgStart);
 
326
   specHalfLineBreakState(sHalfLineBreakAtMsgStart, sMsgStart);
 
327
   specDefaultTransition(sScanStatusLine, taNone, sScanStatusLine);
 
328
   specTransition(sScanStatusLine,
 
329
                  ccCarriageReturn,
 
330
                  taTermStatusLine,
 
331
                  sHalfLineBreakAfterStatusLine);
 
332
   specHalfLineBreakState(sHalfLineBreakAfterStatusLine,
 
333
                          sAfterLineBreakAfterStatusLine);
 
334
   specDefaultTransition(sAfterLineBreakAfterStatusLine,
 
335
                         taError,
 
336
                         sAfterLineBreakAfterStatusLine);
 
337
   specTransition(sAfterLineBreakAfterStatusLine,
 
338
                  ccFieldName,
 
339
                  taStartText,
 
340
                  sScanFieldName);
 
341
   specTransition(sAfterLineBreakAfterStatusLine,
 
342
                  ccWhitespace,
 
343
                  taError,
 
344
                  sAfterLineBreakAfterStatusLine);
 
345
   specTransition(sAfterLineBreakAfterStatusLine,
 
346
                  ccCarriageReturn,
 
347
                  taNone,
 
348
                  sHalfLineBreakAfterLineBreak);
 
349
   specDefaultTransition(sScanFieldName, taError, sScanFieldName);
 
350
   specTransition(sScanFieldName, ccFieldName, taNone, sScanFieldName);
 
351
   specTransition(sScanFieldName,
 
352
                  ccWhitespace,
 
353
                  taTermFieldName,
 
354
                  sScanWhitespaceAfter1FieldName);
 
355
   specTransition(sScanFieldName,
 
356
                  ccColon,
 
357
                  taTermFieldName,
 
358
                  sScanWhitespaceOr1Value);
 
359
   specXValueStates(0);
 
360
   specXValueStates(deltaOfNStateFrom1State);
 
361
   specDefaultTransition(sScanNValueInQuotes, taNone, sScanNValueInQuotes);
 
362
   specTransition(sScanNValueInQuotes,
 
363
                  ccDoubleQuotationMark,
 
364
                  taNone,
 
365
                  sScanNValue);
 
366
   specTransition(sScanNValueInQuotes,
 
367
                  ccBackslash,
 
368
                  taNone,
 
369
                  sAfterEscCharInQuotesInNValue);
 
370
   specTransition(sScanNValueInQuotes,
 
371
                  ccCarriageReturn,
 
372
                  taNone,
 
373
                  sHalfLineBreakInQuotesInNValue);
 
374
   specDefaultTransition(sAfterEscCharInQuotesInNValue,
 
375
                         taNone,
 
376
                         sScanNValueInQuotes);
 
377
   specHalfLineBreakState(sHalfLineBreakInQuotesInNValue,
 
378
                          sAfterLineBreakInQuotesInNValue);
 
379
   specDefaultTransition(sAfterLineBreakInQuotesInNValue,
 
380
                         taError,
 
381
                         sAfterLineBreakInQuotesInNValue);
 
382
   specTransition(sAfterLineBreakInQuotesInNValue,
 
383
                  ccWhitespace,
 
384
                  taNone,
 
385
                  sScanNValueInQuotes);
 
386
   specDefaultTransition(sScanNValueInAngles, taNone, sScanNValueInAngles);
 
387
   specTransition(sScanNValueInAngles,
 
388
                  ccRightAngleBracket,
 
389
                  taNone,
 
390
                  sScanNValue);
 
391
   specTransition(sScanNValueInAngles,
 
392
                  ccCarriageReturn,
 
393
                  taNone,
 
394
                  sHalfLineBreakInAnglesInNValue);
 
395
   specHalfLineBreakState(sHalfLineBreakInAnglesInNValue,
 
396
                          sAfterLineBreakInAnglesInNValue);
 
397
   specDefaultTransition(sAfterLineBreakInAnglesInNValue,
 
398
                         taError,
 
399
                         sAfterLineBreakInAnglesInNValue);
 
400
   specTransition(sAfterLineBreakInAnglesInNValue,
 
401
                  ccWhitespace,
 
402
                  taNone,
 
403
                  sScanNValueInAngles);
 
404
   specHalfLineBreakState(sHalfLineBreakAfterLineBreak, sMsgStart);
 
405
 
 
406
   // Most half-line-break states do nothing when they read a line feed,
 
407
   // but sHalfLineBreakAfterLineBreak must end the message header scanning.
 
408
 
 
409
   specTransition(sHalfLineBreakAfterLineBreak,
 
410
                  ccLineFeed,
 
411
                  taEndHeader,
 
412
                  sMsgStart); // Arbitrary but possibly handy.
 
413
}
 
414
 
 
415
// Debug follows
 
416
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)  
 
417
 
 
418
static void printText(const char *  text,
 
419
                      unsigned int  textLength)
 
420
{
 
421
   const char *charPtr = text;
 
422
   for (unsigned int counter = 0; counter < textLength; ++charPtr, ++counter)
 
423
   {
 
424
      char c = *charPtr;
 
425
      switch (c)
 
426
      {
 
427
         case '\\': printf("\\\\");
 
428
            break;
 
429
         case '\r': printf("\\r");
 
430
            break;
 
431
         case '\n': printf("\\n");
 
432
            break;
 
433
         case '\t': printf("\\t");
 
434
            break;
 
435
         case '\0': printf("\\0");
 
436
            break;
 
437
         default:   putchar(c);
 
438
      }
 
439
   }
 
440
}
 
441
 
 
442
static const char *
 
443
categorySymbol(CharCategory c)
 
444
{
 
445
   switch(c)
 
446
   {
 
447
      case ccChunkTermSentinel: return "TERM";
 
448
      case ccOther: return "*";
 
449
      case ccFieldName: return "FName";
 
450
      case ccWhitespace: return "WS";
 
451
      case ccColon: return "\\\":\\\"";
 
452
      case ccDoubleQuotationMark: return "\\\"";
 
453
      case ccLeftAngleBracket: return "\\\"<\\\"";
 
454
      case ccRightAngleBracket: return "\\\">\\\"";
 
455
      case ccBackslash: return "\\\"\\\\\\\"";
 
456
      case ccComma: return "\\\",\\\"";
 
457
      case ccCarriageReturn: return "CR";
 
458
      case ccLineFeed: return "LF";
 
459
   }
 
460
   return "??CC??";
 
461
}
 
462
 
 
463
static const char *
 
464
categoryName(CharCategory c)
 
465
{
 
466
   switch(c)
 
467
   {
 
468
      case ccChunkTermSentinel: return "ccChunkTermSentinel";
 
469
      case ccOther: return "ccOther";
 
470
      case ccFieldName: return "ccFieldName";
 
471
      case ccWhitespace: return "ccWhitespace";
 
472
      case ccColon: return "ccColon";
 
473
      case ccDoubleQuotationMark: return "ccDoubleQuotationMark";
 
474
      case ccLeftAngleBracket: return "ccLeftAngleBracket";
 
475
      case ccRightAngleBracket: return "ccRightAngleBracket";
 
476
      case ccBackslash: return "ccBackslash";
 
477
      case ccComma: return "ccComma";
 
478
      case ccCarriageReturn: return "ccCarriageReturn";
 
479
      case ccLineFeed: return "ccLineFeed";
 
480
   }
 
481
   return "UNKNOWNCC";
 
482
}
 
483
 
 
484
static const char *
 
485
cleanName(const char * name)
 
486
{
 
487
   // Remove leading type-noise from name
 
488
   static char *leaders[] = {
 
489
      "cc",
 
490
      "s",
 
491
      "taChunkTerm", // hack to make ChunkTermSentinel smaller
 
492
      "ta"
 
493
   };
 
494
   const int nLeaders = sizeof(leaders)/sizeof(*leaders);
 
495
   int offset = 0;
 
496
   for(int i = 0 ; i < nLeaders ; i++)
 
497
   {
 
498
      unsigned int l = strlen(leaders[i]);
 
499
      if (strstr(name,leaders[i]) == name &&
 
500
          strlen(name) > l && 
 
501
          isupper(name[l]))
 
502
      {
 
503
         offset = l;
 
504
         break;
 
505
      }
 
506
   }
 
507
   return &name[offset];
 
508
}
 
509
 
 
510
static const char * 
 
511
stateName(State state)
 
512
{
 
513
   const char *stateName;
 
514
   switch (state) 
 
515
   {
 
516
      case sMsgStart:
 
517
         stateName = "sMsgStart";
 
518
         break;
 
519
      case sHalfLineBreakAtMsgStart:
 
520
         stateName = "sHalfLineBreakAtMsgStart";
 
521
         break;
 
522
      case sScanStatusLine:
 
523
         stateName = "sScanStatusLine";
 
524
         break;
 
525
      case sHalfLineBreakAfterStatusLine:
 
526
         stateName = "sHalfLineBreakAfterStatusLine";
 
527
         break;
 
528
      case sAfterLineBreakAfterStatusLine:
 
529
         stateName = "sAfterLineBreakAfterStatusLine";
 
530
         break;
 
531
      case sScanFieldName:
 
532
         stateName = "sScanFieldName";
 
533
         break;
 
534
      case sScanWhitespaceAfter1FieldName:
 
535
         stateName = "sScanWhitespaceAfter1FieldName";
 
536
         break;
 
537
      case sScanWhitespaceAfterNFieldName:
 
538
         stateName = "sScanWhitespaceAfterNFieldName";
 
539
         break;
 
540
      case sScanWhitespaceOr1Value:
 
541
         stateName = "sScanWhitespaceOr1Value";
 
542
         break;
 
543
      case sScanWhitespaceOrNValue:
 
544
         stateName = "sScanWhitespaceOrNValue";
 
545
         break;
 
546
      case sHalfLineBreakInWhitespaceBefore1Value:
 
547
         stateName = "sHalfLineBreakInWhitespaceBefore1Value";
 
548
         break;
 
549
      case sHalfLineBreakInWhitespaceBeforeNValue:
 
550
         stateName = "sHalfLineBreakInWhitespaceBeforeNValue";
 
551
         break;
 
552
      case sAfterLineBreakInWhitespaceBefore1Value:
 
553
         stateName = "sAfterLineBreakInWhitespaceBefore1Value";
 
554
         break;
 
555
      case sAfterLineBreakInWhitespaceBeforeNValue:
 
556
         stateName = "sAfterLineBreakInWhitespaceBeforeNValue";
 
557
         break;
 
558
      case sScan1Value:
 
559
         stateName = "sScan1Value";
 
560
         break;
 
561
      case sScanNValue:
 
562
         stateName = "sScanNValue";
 
563
         break;
 
564
      case sHalfLineBreakIn1Value:
 
565
         stateName = "sHalfLineBreakIn1Value";
 
566
         break;
 
567
      case sHalfLineBreakInNValue:
 
568
         stateName = "sHalfLineBreakInNValue";
 
569
         break;
 
570
      case sAfterLineBreakIn1Value:
 
571
         stateName = "sAfterLineBreakIn1Value";
 
572
         break;
 
573
      case sAfterLineBreakInNValue:
 
574
         stateName = "sAfterLineBreakInNValue";
 
575
         break;
 
576
      case sScanNValueInQuotes:
 
577
         stateName = "sScanNValueInQuotes";
 
578
         break;
 
579
      case sAfterEscCharInQuotesInNValue:
 
580
         stateName = "sAfterEscCharInQuotesInNValue";
 
581
         break;
 
582
      case sHalfLineBreakInQuotesInNValue:
 
583
         stateName = "sHalfLineBreakInQuotesInNValue";
 
584
         break;
 
585
      case sAfterLineBreakInQuotesInNValue:
 
586
         stateName = "sAfterLineBreakInQuotesInNValue";
 
587
         break;
 
588
      case sScanNValueInAngles:
 
589
         stateName = "sScanNValueInAngles";
 
590
         break;
 
591
      case sHalfLineBreakInAnglesInNValue:
 
592
         stateName = "sHalfLineBreakInAnglesInNValue";
 
593
         break;
 
594
      case sAfterLineBreakInAnglesInNValue:
 
595
         stateName = "sAfterLineBreakInAnglesInNValue";
 
596
         break;
 
597
      case sHalfLineBreakAfterLineBreak:
 
598
         stateName = "sHalfLineBreakAfterLineBreak";
 
599
         break;
 
600
      default:
 
601
         stateName = "<unknown>";
 
602
   }//switch
 
603
   return stateName;
 
604
}
 
605
 
 
606
static const char *
 
607
trActionName(TransitionAction transitionAction)
 
608
{  
 
609
   const char *transitionActionName;
 
610
   switch (transitionAction)
 
611
   {
 
612
      case taNone:
 
613
         transitionActionName = "taNone";
 
614
         break;
 
615
      case taTermStatusLine:
 
616
         transitionActionName = "taTermStatusLine";
 
617
         break;
 
618
      case taTermFieldName:
 
619
         transitionActionName = "taTermFieldName";
 
620
         break;
 
621
      case taBeyondEmptyValue:
 
622
         transitionActionName = "taBeyondEmptyValue";
 
623
         break;
 
624
      case taTermValueAfterLineBreak:
 
625
         transitionActionName = "taTermValueAfterLineBreak";
 
626
         break;
 
627
      case taTermValue:
 
628
         transitionActionName = "taTermValue";
 
629
         break;
 
630
      case taStartText:
 
631
         transitionActionName = "taStartText";
 
632
         break;
 
633
      case taEndHeader:
 
634
         transitionActionName = "taEndHeader";
 
635
         break;
 
636
      case taChunkTermSentinel:
 
637
         transitionActionName = "taChunkTermSentinel";
 
638
         break;
 
639
      case taError:
 
640
         transitionActionName = "taError";
 
641
         break;
 
642
      default:
 
643
         transitionActionName = "<unknown>";
 
644
   }
 
645
   return transitionActionName;
 
646
}
 
647
 
 
648
static void
 
649
printStateTransition(State state,
 
650
                     char character,
 
651
                     TransitionAction transitionAction)
 
652
{
 
653
   printf("                %s['", cleanName(stateName(state)));
 
654
   printText(&character, 1);
 
655
   printf("']: %s\n", cleanName(trActionName(transitionAction)));
 
656
}
 
657
#if !defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
 
658
static const char* stateName(const char*)
 
659
{ return "RECOMPILE_WITH_SCANNER_DEBUG"; }
 
660
static const char* trActionName(const char*)
 
661
{ return stateName(0); }
 
662
#endif
 
663
/// START OF MEMBER METHODS
 
664
 
 
665
 
 
666
 
 
667
int
 
668
MsgHeaderScanner::dumpStateMachine(int fd)
 
669
{
 
670
   FILE *fp = fdopen(fd,"w");
 
671
   if (!fp) 
 
672
   {
 
673
      fprintf(stderr,"MsgHeaderScanner:: unable to open output file\n");
 
674
      return -1;
 
675
   }
 
676
   // Force instance so things are initialized -- YUCK! 
 
677
   MsgHeaderScanner scanner;(void)scanner;
 
678
   fprintf(fp,"digraph MsgHeaderScannerFSM {\n");
 
679
   fprintf(fp,"\tnode[shape=record\n\t\tfontsize=8\n\t\tfontname=\"Helvetica\"\n\t]\n");
 
680
   fprintf(fp,"\tedge [ fontsize=6 fontname=\"Helvetica\"]\n");
 
681
   
 
682
   fprintf(fp,"\tgraph [ ratio=0.8\n\t\tfontsize=6 compound=true ]");
 
683
   for(int state  = 0 ; state < numStates; ++state)
 
684
   {
 
685
      fprintf(fp,
 
686
              "  %s [ label = \"%d|%s\" ]\n",
 
687
              cleanName(stateName(state)),
 
688
              state,
 
689
              cleanName(stateName(state))
 
690
         );
 
691
      for(int category = 0 ; category < numCharCategories; ++category)
 
692
      {
 
693
         // Skip Verbose Error or Empty Transitions
 
694
         if (stateMachine[state][category].nextState == state &&
 
695
             (stateMachine[state][category].action == taError ||
 
696
              stateMachine[state][category].action == taNone
 
697
                )) continue;
 
698
              
 
699
         fprintf(fp,
 
700
                 "    %s -> %s [label=\"%s\\n%s\" ]\n",
 
701
                 cleanName(stateName(state)),
 
702
                 cleanName(stateName(stateMachine[state][category].nextState)),
 
703
                 categorySymbol(category),
 
704
                 cleanName(trActionName(stateMachine[state][category].action)));
 
705
      }
 
706
      fprintf(fp,"\n");
 
707
   }
 
708
   fprintf(fp,"}\n");
 
709
 
 
710
   return 0;
 
711
}
 
712
 
 
713
#endif //defined(RESIP_MSG_HEADER_SCANNER_DEBUG) 
 
714
 
 
715
 
 
716
 
 
717
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)  
 
718
 
 
719
static const char *const multiValuedFieldNameArray[] = {
 
720
   "allow-events",
 
721
   "accept-encoding",
 
722
   "accept-language",
 
723
   "allow",
 
724
   "content-language",
 
725
   "proxy-require",
 
726
   "require",
 
727
   "supported",
 
728
   "subscription-state",
 
729
   "unsupported",
 
730
   "security-client",
 
731
   "security-server",
 
732
   "security-verify",
 
733
   "accept",
 
734
   "call-info",
 
735
   "alert-info",
 
736
   "error-info",
 
737
   "record-route",
 
738
   "route",
 
739
   "contact",
 
740
   "authorization",
 
741
   "proxy-authenticate",
 
742
   "proxy-authorization",
 
743
   "www-authenticate",
 
744
   "via",
 
745
   0
 
746
};
 
747
 
 
748
extern
 
749
void
 
750
lookupMsgHeaderFieldInfo(
 
751
   char *                             fieldName,               //inout
 
752
   unsigned int                       *fieldNameLength,        //inout
 
753
   MsgHeaderScanner::TextPropBitMask  fieldNameTextPropBitMask,
 
754
   int                                *fieldKind,              //out
 
755
   bool                               *isMultiValueAllowed)    //out
 
756
{
 
757
   *isMultiValueAllowed = false;
 
758
   const char *const *multiValuedFieldNamePtr = multiValuedFieldNameArray;
 
759
   for (;;)
 
760
   {
 
761
      const char *multiValuedFieldName = *multiValuedFieldNamePtr;
 
762
      if (!multiValuedFieldName) 
 
763
      {
 
764
         break;
 
765
      }
 
766
      if (strncmp(fieldName, multiValuedFieldName, *fieldNameLength) == 0) 
 
767
      {
 
768
         *isMultiValueAllowed = true;
 
769
         break;
 
770
      }
 
771
      ++multiValuedFieldNamePtr;
 
772
   }//for
 
773
}
 
774
 
 
775
static
 
776
bool
 
777
processMsgHeaderStatusLine(
 
778
   SipMessage *                       msg,
 
779
   char *                             lineText,
 
780
   unsigned int                       lineTextLength,
 
781
   MsgHeaderScanner::TextPropBitMask  lineTextPropBitMask)
 
782
{
 
783
   printf("status line: ");
 
784
   printText(lineText, lineTextLength);
 
785
   printf("\n");
 
786
   return true;
 
787
}
 
788
 
 
789
static
 
790
void
 
791
processMsgHeaderFieldNameAndValue(
 
792
   SipMessage *                       msg,
 
793
   int                                fieldKind,
 
794
   const char *                       fieldName,
 
795
   unsigned int                       fieldNameLength,
 
796
   char *                             valueText,
 
797
   unsigned int                       valueTextLength,
 
798
   MsgHeaderScanner::TextPropBitMask  valueTextPropBitMask)
 
799
{
 
800
   printText(fieldName, fieldNameLength);
 
801
   printf(": [[[[");
 
802
   printText(valueText, valueTextLength);
 
803
   printf("]]]]\n");
 
804
}
 
805
 
 
806
#else //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) } {
 
807
 
 
808
 
 
809
//   Determine a field's kind and whether it allows (comma separated) multi-values.
 
810
//   "fieldName" is not empty and contains only legal characters.
 
811
//   The text in "fieldName" may be canonicalized (eg, translating % escapes),
 
812
//   including shrinking it if necessary.
 
813
 
 
814
inline void
 
815
lookupMsgHeaderFieldInfo(char * fieldName,
 
816
                         unsigned int *fieldNameLength,   
 
817
                         MsgHeaderScanner::TextPropBitMask fieldNameTextPropBitMask,
 
818
                         int *fieldKind,             
 
819
                         bool *isMultiValueAllowed)    
 
820
{
 
821
   //.jacob. Don't ignore fieldNameTextPropBitMask.
 
822
   *fieldKind = Headers::getType(fieldName, *fieldNameLength);
 
823
   *isMultiValueAllowed =
 
824
      Headers::isCommaTokenizing(static_cast<Headers::Type>(*fieldKind));
 
825
}
 
826
 
 
827
 
 
828
// "lineText" contains no carriage returns and no line feeds.
 
829
// Return true on success, false on failure.
 
830
 
 
831
inline bool
 
832
processMsgHeaderStatusLine(SipMessage * msg,
 
833
                           char * lineText,
 
834
                           unsigned int lineTextLength,
 
835
                           MsgHeaderScanner::TextPropBitMask lineTextPropBitMask)
 
836
{
 
837
   //.jacob. Don't ignore valueTextPropBitMask, and don't always return true.
 
838
   msg->setStartLine(lineText, lineTextLength);
 
839
   return true;
 
840
}
 
841
 
 
842
// This function is called once for a field with one value.  (The value could be
 
843
// several values, but separated by something other than commas.)
 
844
// This function is called once for a field with 0 comma-separated values, with
 
845
// an empty value.
 
846
// This function is called N times for a field with N comma-separated values,
 
847
// but with the same value of "fieldName" each time.
 
848
// "fieldName" is not empty and contains only legal characters.
 
849
// "valueText" may be empty, has no leading whitespace, may contain trailing
 
850
// whitespace, contains carriage returns and line feeds only in correct pairs
 
851
// and followed by whitespace, and, if the field is multi-valued, contains
 
852
// balanced '<'/'>' and '"' pairs, contains ',' only within '<'/'>' or '"'
 
853
// pairs, and respects '\\'s within '"' pairs.
 
854
// The text in "valueText" may be canonicalized (eg, translating % escapes),
 
855
// including shrinking it if necessary.
 
856
 
 
857
inline void
 
858
processMsgHeaderFieldNameAndValue(SipMessage * msg,
 
859
                                  int fieldKind,
 
860
                                  const char * fieldName,
 
861
                                  unsigned int fieldNameLength,
 
862
                                  char * valueText,
 
863
                                  unsigned int valueTextLength,
 
864
                                  MsgHeaderScanner::TextPropBitMask valueTextPropBitMask)
 
865
{
 
866
   //.jacob. Don't ignore valueTextPropBitMask, particularly for '\r' & '\n'.
 
867
   msg->addHeader(static_cast<Headers::Type>(fieldKind),
 
868
                  fieldName,
 
869
                  fieldNameLength,
 
870
                  valueText,
 
871
                  valueTextLength);
 
872
}
 
873
 
 
874
#endif //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) }
 
875
 
 
876
bool MsgHeaderScanner::mInitialized = false;
 
877
 
 
878
MsgHeaderScanner::MsgHeaderScanner()
 
879
{
 
880
   if (!mInitialized)
 
881
   {
 
882
      mInitialized = true;
 
883
      initialize();
 
884
   }
 
885
}
 
886
 
 
887
void
 
888
MsgHeaderScanner::prepareForMessage(SipMessage *  msg)
 
889
{
 
890
   mMsg = msg;
 
891
   mState = sMsgStart;
 
892
   mPrevScanChunkNumSavedTextChars = 0;
 
893
   mNumHeaders=0;
 
894
}
 
895
 
 
896
void
 
897
MsgHeaderScanner::prepareForFrag(SipMessage *  msg, bool hasStartLine)
 
898
{
 
899
   mMsg = msg;
 
900
   if (hasStartLine)
 
901
   {
 
902
      mState = sMsgStart;
 
903
   }
 
904
   else
 
905
   {
 
906
      mState = sAfterLineBreakAfterStatusLine;
 
907
   }
 
908
   mPrevScanChunkNumSavedTextChars = 0;
 
909
   mNumHeaders=0;
 
910
}
 
911
 
 
912
MsgHeaderScanner::ScanChunkResult
 
913
MsgHeaderScanner::scanChunk(char * chunk,
 
914
                            unsigned int chunkLength,
 
915
                            char ** unprocessedCharPtr)
 
916
{
 
917
   MsgHeaderScanner::ScanChunkResult result;
 
918
   CharInfo* localCharInfoArray = charInfoArray;
 
919
   TransitionInfo (*localStateMachine)[numCharCategories] = stateMachine;
 
920
   State localState = mState;
 
921
   char *charPtr = chunk + mPrevScanChunkNumSavedTextChars;
 
922
   char *termCharPtr = chunk + chunkLength;
 
923
   char saveChunkTermChar = *termCharPtr;
 
924
   *termCharPtr = chunkTermSentinelChar;
 
925
   char *textStartCharPtr;
 
926
   MsgHeaderScanner::TextPropBitMask localTextPropBitMask = mTextPropBitMask;
 
927
   if (mPrevScanChunkNumSavedTextChars == 0)
 
928
   {
 
929
      textStartCharPtr = 0;
 
930
   }
 
931
   else
 
932
   {
 
933
      textStartCharPtr = chunk;
 
934
   }
 
935
   --charPtr;  // The loop starts by advancing "charPtr", so pre-adjust it.
 
936
   for (;;)
 
937
   {
 
938
      // BEGIN message header character scan block BEGIN
 
939
      // The code in this block is executed once per message header character.
 
940
      // This entire file is designed specifically to minimize this block's size.
 
941
      ++charPtr;
 
942
      CharInfo *charInfo = &localCharInfoArray[((unsigned char) (*charPtr))];
 
943
      CharCategory charCategory = charInfo->category;
 
944
      localTextPropBitMask |= charInfo->textPropBitMask;
 
945
     determineTransitionFromCharCategory:
 
946
      TransitionInfo *transitionInfo =
 
947
         &(localStateMachine[(unsigned)localState][(size_t)charCategory]);
 
948
      TransitionAction transitionAction = transitionInfo->action;
 
949
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)  
 
950
      printStateTransition(localState, *charPtr, transitionAction);
 
951
#endif
 
952
      localState = transitionInfo->nextState;
 
953
      if (transitionAction == taNone) continue;
 
954
      // END message header character scan block END
 
955
      // The loop remainder is executed about 4-5 times per message header line.
 
956
      switch (transitionAction)
 
957
      {
 
958
         case taTermStatusLine:
 
959
            if (!processMsgHeaderStatusLine(mMsg,
 
960
                                            textStartCharPtr,
 
961
                                            (unsigned int)(charPtr - textStartCharPtr),
 
962
                                            localTextPropBitMask))
 
963
            {
 
964
               result = MsgHeaderScanner::scrError;
 
965
               *unprocessedCharPtr = charPtr;
 
966
               goto endOfFunction;
 
967
            }
 
968
            textStartCharPtr = 0;
 
969
            break;
 
970
         case taTermFieldName:
 
971
         {
 
972
            mFieldNameLength = (unsigned int)(charPtr - textStartCharPtr);
 
973
            bool isMultiValueAllowed;
 
974
            lookupMsgHeaderFieldInfo(textStartCharPtr,
 
975
                                     &mFieldNameLength,
 
976
                                     localTextPropBitMask,
 
977
                                     &mFieldKind,
 
978
                                     &isMultiValueAllowed);
 
979
            mFieldName = textStartCharPtr;
 
980
            textStartCharPtr = 0;
 
981
            if (isMultiValueAllowed) 
 
982
            {
 
983
               localState += deltaOfNStateFrom1State;
 
984
            }
 
985
         }
 
986
         break;
 
987
         case taBeyondEmptyValue:
 
988
            processMsgHeaderFieldNameAndValue(mMsg,
 
989
                                              mFieldKind,
 
990
                                              mFieldName,
 
991
                                              mFieldNameLength,
 
992
                                              0,
 
993
                                              0,
 
994
                                              0);
 
995
            ++mNumHeaders;
 
996
            goto performStartTextAction;
 
997
         case taTermValueAfterLineBreak:
 
998
            processMsgHeaderFieldNameAndValue(mMsg,
 
999
                                              mFieldKind,
 
1000
                                              mFieldName,
 
1001
                                              mFieldNameLength,
 
1002
                                              textStartCharPtr,
 
1003
                                              (unsigned int)((charPtr - textStartCharPtr) - 2),
 
1004
                                              localTextPropBitMask);       //^:CRLF
 
1005
            ++mNumHeaders;
 
1006
            goto performStartTextAction;
 
1007
         case taTermValue:
 
1008
            processMsgHeaderFieldNameAndValue(mMsg,
 
1009
                                              mFieldKind,
 
1010
                                              mFieldName,
 
1011
                                              mFieldNameLength,
 
1012
                                              textStartCharPtr,
 
1013
                                              (unsigned int)(charPtr - textStartCharPtr),
 
1014
                                              localTextPropBitMask);
 
1015
            textStartCharPtr = 0;
 
1016
            ++mNumHeaders;
 
1017
            break;
 
1018
         case taStartText:
 
1019
        performStartTextAction:
 
1020
            textStartCharPtr = charPtr;
 
1021
            localTextPropBitMask = 0;
 
1022
            break;
 
1023
         case taEndHeader:
 
1024
            // textStartCharPtr is not 0.  Not currently relevant.
 
1025
            result = MsgHeaderScanner::scrEnd;
 
1026
            *unprocessedCharPtr = charPtr + 1;  // The current char is processed.
 
1027
            goto endOfFunction;
 
1028
            break;
 
1029
         case taChunkTermSentinel:
 
1030
            if (charPtr == termCharPtr)
 
1031
            {
 
1032
               // The chunk has been consumed.  Save some state and request another.
 
1033
               mState = localState;
 
1034
               if (textStartCharPtr == 0) 
 
1035
               {
 
1036
                  mPrevScanChunkNumSavedTextChars = 0;
 
1037
               }
 
1038
               else
 
1039
               {
 
1040
                  mPrevScanChunkNumSavedTextChars = (unsigned int)(termCharPtr - textStartCharPtr);
 
1041
               }
 
1042
               mTextPropBitMask = localTextPropBitMask;
 
1043
               result = MsgHeaderScanner::scrNextChunk;
 
1044
               *unprocessedCharPtr = termCharPtr - mPrevScanChunkNumSavedTextChars;
 
1045
               goto endOfFunction;
 
1046
            }
 
1047
            else
 
1048
            {
 
1049
               // The character is not the sentinel.  Treat it like any other.
 
1050
               charCategory = ccOther;
 
1051
               goto determineTransitionFromCharCategory;
 
1052
            }
 
1053
            break;
 
1054
         default:
 
1055
            result = MsgHeaderScanner::scrError;
 
1056
            *unprocessedCharPtr = charPtr;
 
1057
            goto endOfFunction;
 
1058
      }//switch
 
1059
   }//for
 
1060
  endOfFunction:
 
1061
   *termCharPtr = saveChunkTermChar;
 
1062
   return result;
 
1063
}
 
1064
 
 
1065
bool
 
1066
MsgHeaderScanner::initialize()
 
1067
{
 
1068
   initCharInfoArray();
 
1069
   initStateMachine();
 
1070
   return true;
 
1071
}
 
1072
 
 
1073
 
 
1074
} //namespace resip
 
1075
 
 
1076
 
 
1077
 
 
1078
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG) && defined(MSG_SCANNER_STANDALONE)
 
1079
 
 
1080
extern
 
1081
int
 
1082
main(unsigned int   numArgs,
 
1083
     const char * * argVector)
 
1084
{
 
1085
   ::resip::MsgHeaderScanner scanner;
 
1086
   scanner.prepareForMessage(0);
 
1087
   char *text =
 
1088
      "status\r\n"
 
1089
      "bobby: dummy\r\n"
 
1090
      "allow: foo, bar, \"don,\\\"xyz\r\n zy\", buzz\r\n\r\n";
 
1091
   unsigned int textLength = strlen(text);
 
1092
   char chunk[10000];
 
1093
   strcpy(chunk, text);
 
1094
   ::resip::MsgHeaderScanner::ScanChunkResult scanChunkResult;
 
1095
   char *unprocessedCharPtr;
 
1096
   scanChunkResult = scanner.scanChunk(chunk, 21, &unprocessedCharPtr);
 
1097
   if (scanChunkResult == ::resip::MsgHeaderScanner::scrNextChunk)
 
1098
   {
 
1099
      printf("Scanning another chunk '.");
 
1100
      ::resip::printText(unprocessedCharPtr, 1);
 
1101
      printf("'\n");
 
1102
      scanChunkResult =
 
1103
         scanner.scanChunk(unprocessedCharPtr,
 
1104
                           (chunk + textLength) - unprocessedCharPtr,
 
1105
                           &unprocessedCharPtr);
 
1106
   }
 
1107
   if (scanChunkResult != ::resip::MsgHeaderScanner::scrEnd)
 
1108
   {
 
1109
      printf("Error %d at character %d.\n",
 
1110
             scanChunkResult,
 
1111
             unprocessedCharPtr - chunk);
 
1112
   }
 
1113
   return 0;
 
1114
}
 
1115
 
 
1116
#endif //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) }
 
1117
 
 
1118
/* ====================================================================
 
1119
 * The Vovida Software License, Version 1.0 
 
1120
 * 
 
1121
 * Copyright (c) 2000-2005
 
1122
 * 
 
1123
 * Redistribution and use in source and binary forms, with or without
 
1124
 * modification, are permitted provided that the following conditions
 
1125
 * are met:
 
1126
 * 
 
1127
 * 1. Redistributions of source code must retain the above copyright
 
1128
 *    notice, this list of conditions and the following disclaimer.
 
1129
 * 
 
1130
 * 2. Redistributions in binary form must reproduce the above copyright
 
1131
 *    notice, this list of conditions and the following disclaimer in
 
1132
 *    the documentation and/or other materials provided with the
 
1133
 *    distribution.
 
1134
 * 
 
1135
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
 
1136
 *    and "Vovida Open Communication Application Library (VOCAL)" must
 
1137
 *    not be used to endorse or promote products derived from this
 
1138
 *    software without prior written permission. For written
 
1139
 *    permission, please contact vocal@vovida.org.
 
1140
 *
 
1141
 * 4. Products derived from this software may not be called "VOCAL", nor
 
1142
 *    may "VOCAL" appear in their name, without prior written
 
1143
 *    permission of Vovida Networks, Inc.
 
1144
 * 
 
1145
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 
1146
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
1147
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
 
1148
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
 
1149
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
 
1150
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
 
1151
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
1152
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
1153
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
1154
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
1155
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 
1156
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 
1157
 * DAMAGE.
 
1158
 * 
 
1159
 * ====================================================================
 
1160
 * 
 
1161
 * This software consists of voluntary contributions made by Vovida
 
1162
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
 
1163
 * Inc.  For more information on Vovida Networks, Inc., please see
 
1164
 * <http://www.vovida.org/>.
 
1165
 *
 
1166
 */