📄 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 + -