📄 msgheaderscanner.cxx
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include "resip/stack/HeaderTypes.hxx"
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/MsgHeaderScanner.hxx"
#include "rutil/WinLeakCheck.hxx"
namespace resip
{
///////////////////////////////////////////////////////////////////////////////
// Any character could be used as the chunk terminating sentinel, as long as
// it would otherwise be character category "other". The null character
// was chosen because it is unlikely to occur naturally -- but it's OK if it
// does.
enum { chunkTermSentinelChar = '\0' };
enum CharCategoryEnum
{
ccChunkTermSentinel,
ccOther,
ccFieldName,
ccWhitespace,
ccColon,
ccDoubleQuotationMark,
ccLeftAngleBracket,
ccRightAngleBracket,
ccBackslash,
ccComma,
ccCarriageReturn,
ccLineFeed,
numCharCategories
};
typedef char CharCategory;
char*
MsgHeaderScanner::allocateBuffer(int size)
{
return new char[size + MaxNumCharsChunkOverflow];
}
struct CharInfo
{
CharCategory category;
MsgHeaderScanner::TextPropBitMask textPropBitMask;
};
static CharInfo charInfoArray[UCHAR_MAX+1];
static inline int c2i(unsigned char c)
{
return static_cast<int>(c);
}
static void initCharInfoArray()
{
for(unsigned int charIndex = 0; charIndex <= UCHAR_MAX; ++charIndex)
{
charInfoArray[charIndex].category = ccOther;
charInfoArray[charIndex].textPropBitMask = 0;
}
for(const char *charPtr = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.!%*_+`'~";
*charPtr;
++charPtr)
{
charInfoArray[c2i(*charPtr)].category = ccFieldName;
}
charInfoArray[c2i(' ')].category = ccWhitespace;
charInfoArray[c2i('\t')].category = ccWhitespace;
charInfoArray[c2i(':')].category = ccColon;
charInfoArray[c2i('"')].category = ccDoubleQuotationMark;
charInfoArray[c2i('<')].category = ccLeftAngleBracket;
charInfoArray[c2i('>')].category = ccRightAngleBracket;
charInfoArray[c2i('\\')].category = ccBackslash;
charInfoArray[c2i(',')].category = ccComma;
charInfoArray[c2i('\r')].category = ccCarriageReturn;
charInfoArray[c2i('\n')].category = ccLineFeed;
// Assert: "chunkTermSentinelChar"'s category is still the default "ccOther".
charInfoArray[c2i(chunkTermSentinelChar)].category = ccChunkTermSentinel;
// Init text property bit masks.
charInfoArray[c2i('\r')].textPropBitMask =
MsgHeaderScanner::tpbmContainsLineBreak;
charInfoArray[c2i('\n')].textPropBitMask =
MsgHeaderScanner::tpbmContainsLineBreak;
charInfoArray[c2i(' ')].textPropBitMask =
MsgHeaderScanner::tpbmContainsWhitespace;
charInfoArray[c2i('\t')].textPropBitMask =
MsgHeaderScanner::tpbmContainsWhitespace;
charInfoArray[c2i('\\')].textPropBitMask =
MsgHeaderScanner::tpbmContainsBackslash;
charInfoArray[c2i('%')].textPropBitMask =
MsgHeaderScanner::tpbmContainsPercent;
charInfoArray[c2i(';')].textPropBitMask =
MsgHeaderScanner::tpbmContainsSemicolon;
charInfoArray[c2i('(')].textPropBitMask =
MsgHeaderScanner::tpbmContainsParen;
charInfoArray[c2i(')')].textPropBitMask =
MsgHeaderScanner::tpbmContainsParen;
}
///////////////////////////////////////////////////////////////////////////////
// States marked '1' scan normal values. States marked 'N' scan multi-values.
enum StateEnum
{
sMsgStart,
sHalfLineBreakAtMsgStart,
sScanStatusLine,
sHalfLineBreakAfterStatusLine,
sAfterLineBreakAfterStatusLine,
sScanFieldName,
sScanWhitespaceAfter1FieldName,
sScanWhitespaceAfterNFieldName,
sScanWhitespaceOr1Value,
sScanWhitespaceOrNValue,
sHalfLineBreakInWhitespaceBefore1Value,
sHalfLineBreakInWhitespaceBeforeNValue,
sAfterLineBreakInWhitespaceBefore1Value,
sAfterLineBreakInWhitespaceBeforeNValue,
sScan1Value,
sScanNValue,
sHalfLineBreakIn1Value,
sHalfLineBreakInNValue,
sAfterLineBreakIn1Value,
sAfterLineBreakInNValue,
sScanNValueInQuotes,
sAfterEscCharInQuotesInNValue,
sHalfLineBreakInQuotesInNValue,
sAfterLineBreakInQuotesInNValue,
sScanNValueInAngles,
sHalfLineBreakInAnglesInNValue,
sAfterLineBreakInAnglesInNValue,
sHalfLineBreakAfterLineBreak,
numStates
};
typedef char State;
// For each '1' state, the 'N' state is "deltaOfNStateFrom1State" larger.
enum { deltaOfNStateFrom1State = 1 };
/////
enum TransitionActionEnum {
taNone,
taTermStatusLine, // The current character terminates the status
// line.
taTermFieldName, // The current character terminates a field name.
// If the field supports multi-values, shift
// the state machine into multi-value scanning.
taBeyondEmptyValue, // The current character terminates an empty value.
// Implies taStartText.
taTermValueAfterLineBreak,
// The previous two characters are a linebreak
// terminating a value. Implies taStartText.
taTermValue, // The current character terminates a value.
taStartText, // The current character starts a text unit.
// (The status line, a field name, or a value.)
taEndHeader, // The current character mEnds_ the header.
taChunkTermSentinel, // Either the current character terminates the
// current chunk or it is an ordinary character.
taError // The input is erroneous.
};
typedef char TransitionAction;
struct TransitionInfo
{
TransitionAction action;
State nextState;
};
static TransitionInfo stateMachine[numStates][numCharCategories];
inline void specTransition(State state,
CharCategory charCategory,
TransitionAction action,
State nextState)
{
stateMachine[c2i(state)][c2i(charCategory)].action = action;
stateMachine[c2i(state)][c2i(charCategory)].nextState = nextState;
}
static void specDefaultTransition(State state,
TransitionAction action,
State nextState)
{
for (int charCategory = 0;
charCategory < numCharCategories;
++charCategory)
{
specTransition(state, charCategory, action, nextState);
}
specTransition(state, ccCarriageReturn, taError, state);
specTransition(state, ccLineFeed, taError, state);
specTransition(state, ccChunkTermSentinel, taChunkTermSentinel, state);
}
static void specHalfLineBreakState(State halfLineBreakState,
State afterLineBreakState)
{
specDefaultTransition(halfLineBreakState, taError, halfLineBreakState);
specTransition(halfLineBreakState, ccLineFeed, taNone, afterLineBreakState);
}
// Single-value (1) scanning and multi-value (N) scanning involves several nearly
// identical states.
// "stateDelta" is either 0 or "deltaOfNStateFrom1State".
static void specXValueStates(int stateDelta)
{
specDefaultTransition(sScanWhitespaceAfter1FieldName + stateDelta,
taError,
sScanWhitespaceAfter1FieldName + stateDelta);
specTransition(sScanWhitespaceAfter1FieldName + stateDelta,
ccWhitespace,
taNone,
sScanWhitespaceAfter1FieldName + stateDelta);
specTransition(sScanWhitespaceAfter1FieldName + stateDelta,
ccColon,
taNone,
sScanWhitespaceOr1Value + stateDelta);
specDefaultTransition(sScanWhitespaceOr1Value + stateDelta,
taStartText,
sScan1Value + stateDelta);
specTransition(sScanWhitespaceOr1Value + stateDelta,
ccWhitespace,
taNone,
sScanWhitespaceOr1Value + stateDelta);
if (stateDelta == deltaOfNStateFrom1State)
{
specTransition(sScanWhitespaceOr1Value + stateDelta,
ccComma,
taError,
sScanWhitespaceOr1Value + stateDelta);
specTransition(sScanWhitespaceOr1Value + stateDelta,
ccLeftAngleBracket,
taStartText,
sScanNValueInAngles);
specTransition(sScanWhitespaceOr1Value + stateDelta,
ccDoubleQuotationMark,
taStartText,
sScanNValueInQuotes);
}
specTransition(sScanWhitespaceOr1Value + stateDelta,
ccCarriageReturn,
taNone,
sHalfLineBreakInWhitespaceBefore1Value + stateDelta);
specHalfLineBreakState(sHalfLineBreakInWhitespaceBefore1Value + stateDelta,
sAfterLineBreakInWhitespaceBefore1Value + stateDelta);
specDefaultTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
taError,
sAfterLineBreakInWhitespaceBefore1Value + stateDelta);
specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
ccFieldName,
taBeyondEmptyValue,
sScanFieldName);
specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
ccWhitespace,
taNone,
sScanWhitespaceOr1Value + stateDelta);
specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
ccCarriageReturn,
taBeyondEmptyValue,
sHalfLineBreakAfterLineBreak);
specDefaultTransition(sScan1Value + stateDelta,
taNone,
sScan1Value + stateDelta);
if (stateDelta == deltaOfNStateFrom1State)
{
specTransition(sScan1Value + stateDelta,
ccComma,
taTermValue,
sScanWhitespaceOr1Value + stateDelta);
specTransition(sScan1Value + stateDelta,
ccLeftAngleBracket,
taNone,
sScanNValueInAngles);
specTransition(sScan1Value + stateDelta,
ccDoubleQuotationMark,
taNone,
sScanNValueInQuotes);
}
specTransition(sScan1Value + stateDelta,
ccCarriageReturn,
taNone,
sHalfLineBreakIn1Value + stateDelta);
specHalfLineBreakState(sHalfLineBreakIn1Value + stateDelta,
sAfterLineBreakIn1Value + stateDelta);
specDefaultTransition(sAfterLineBreakIn1Value + stateDelta,
taError,
sAfterLineBreakIn1Value + stateDelta);
specTransition(sAfterLineBreakIn1Value + stateDelta,
ccFieldName,
taTermValueAfterLineBreak,
sScanFieldName);
specTransition(sAfterLineBreakIn1Value + stateDelta,
ccWhitespace,
taNone,
sScan1Value + stateDelta);
specTransition(sAfterLineBreakIn1Value + stateDelta,
ccCarriageReturn,
taTermValueAfterLineBreak,
sHalfLineBreakAfterLineBreak);
}
static void initStateMachine()
{
// By convention, error transitions maintain the same state.
specDefaultTransition(sMsgStart, taStartText, sScanStatusLine);
specTransition(sMsgStart,
ccCarriageReturn,
taNone,
sHalfLineBreakAtMsgStart);
specTransition(sMsgStart, ccLineFeed, taError, sMsgStart);
specHalfLineBreakState(sHalfLineBreakAtMsgStart, sMsgStart);
specDefaultTransition(sScanStatusLine, taNone, sScanStatusLine);
specTransition(sScanStatusLine,
ccCarriageReturn,
taTermStatusLine,
sHalfLineBreakAfterStatusLine);
specHalfLineBreakState(sHalfLineBreakAfterStatusLine,
sAfterLineBreakAfterStatusLine);
specDefaultTransition(sAfterLineBreakAfterStatusLine,
taError,
sAfterLineBreakAfterStatusLine);
specTransition(sAfterLineBreakAfterStatusLine,
ccFieldName,
taStartText,
sScanFieldName);
specTransition(sAfterLineBreakAfterStatusLine,
ccWhitespace,
taError,
sAfterLineBreakAfterStatusLine);
specTransition(sAfterLineBreakAfterStatusLine,
ccCarriageReturn,
taNone,
sHalfLineBreakAfterLineBreak);
specDefaultTransition(sScanFieldName, taError, sScanFieldName);
specTransition(sScanFieldName, ccFieldName, taNone, sScanFieldName);
specTransition(sScanFieldName,
ccWhitespace,
taTermFieldName,
sScanWhitespaceAfter1FieldName);
specTransition(sScanFieldName,
ccColon,
taTermFieldName,
sScanWhitespaceOr1Value);
specXValueStates(0);
specXValueStates(deltaOfNStateFrom1State);
specDefaultTransition(sScanNValueInQuotes, taNone, sScanNValueInQuotes);
specTransition(sScanNValueInQuotes,
ccDoubleQuotationMark,
taNone,
sScanNValue);
specTransition(sScanNValueInQuotes,
ccBackslash,
taNone,
sAfterEscCharInQuotesInNValue);
specTransition(sScanNValueInQuotes,
ccCarriageReturn,
taNone,
sHalfLineBreakInQuotesInNValue);
specDefaultTransition(sAfterEscCharInQuotesInNValue,
taNone,
sScanNValueInQuotes);
specHalfLineBreakState(sHalfLineBreakInQuotesInNValue,
sAfterLineBreakInQuotesInNValue);
specDefaultTransition(sAfterLineBreakInQuotesInNValue,
taError,
sAfterLineBreakInQuotesInNValue);
specTransition(sAfterLineBreakInQuotesInNValue,
ccWhitespace,
taNone,
sScanNValueInQuotes);
specDefaultTransition(sScanNValueInAngles, taNone, sScanNValueInAngles);
specTransition(sScanNValueInAngles,
ccRightAngleBracket,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -