📄 msgheaderscanner.cxx
字号:
taNone,
sScanNValue);
specTransition(sScanNValueInAngles,
ccCarriageReturn,
taNone,
sHalfLineBreakInAnglesInNValue);
specHalfLineBreakState(sHalfLineBreakInAnglesInNValue,
sAfterLineBreakInAnglesInNValue);
specDefaultTransition(sAfterLineBreakInAnglesInNValue,
taError,
sAfterLineBreakInAnglesInNValue);
specTransition(sAfterLineBreakInAnglesInNValue,
ccWhitespace,
taNone,
sScanNValueInAngles);
specHalfLineBreakState(sHalfLineBreakAfterLineBreak, sMsgStart);
// Most half-line-break states do nothing when they read a line feed,
// but sHalfLineBreakAfterLineBreak must end the message header scanning.
specTransition(sHalfLineBreakAfterLineBreak,
ccLineFeed,
taEndHeader,
sMsgStart); // Arbitrary but possibly handy.
}
// Debug follows
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
static void printText(const char * text,
unsigned int textLength)
{
const char *charPtr = text;
for (unsigned int counter = 0; counter < textLength; ++charPtr, ++counter)
{
char c = *charPtr;
switch (c)
{
case '\\': printf("\\\\");
break;
case '\r': printf("\\r");
break;
case '\n': printf("\\n");
break;
case '\t': printf("\\t");
break;
case '\0': printf("\\0");
break;
default: putchar(c);
}
}
}
static const char *
categorySymbol(CharCategory c)
{
switch(c)
{
case ccChunkTermSentinel: return "TERM";
case ccOther: return "*";
case ccFieldName: return "FName";
case ccWhitespace: return "WS";
case ccColon: return "\\\":\\\"";
case ccDoubleQuotationMark: return "\\\"";
case ccLeftAngleBracket: return "\\\"<\\\"";
case ccRightAngleBracket: return "\\\">\\\"";
case ccBackslash: return "\\\"\\\\\\\"";
case ccComma: return "\\\",\\\"";
case ccCarriageReturn: return "CR";
case ccLineFeed: return "LF";
}
return "??CC??";
}
static const char *
categoryName(CharCategory c)
{
switch(c)
{
case ccChunkTermSentinel: return "ccChunkTermSentinel";
case ccOther: return "ccOther";
case ccFieldName: return "ccFieldName";
case ccWhitespace: return "ccWhitespace";
case ccColon: return "ccColon";
case ccDoubleQuotationMark: return "ccDoubleQuotationMark";
case ccLeftAngleBracket: return "ccLeftAngleBracket";
case ccRightAngleBracket: return "ccRightAngleBracket";
case ccBackslash: return "ccBackslash";
case ccComma: return "ccComma";
case ccCarriageReturn: return "ccCarriageReturn";
case ccLineFeed: return "ccLineFeed";
}
return "UNKNOWNCC";
}
static const char *
cleanName(const char * name)
{
// Remove leading type-noise from name
static char *leaders[] = {
"cc",
"s",
"taChunkTerm", // hack to make ChunkTermSentinel smaller
"ta"
};
const int nLeaders = sizeof(leaders)/sizeof(*leaders);
int offset = 0;
for(int i = 0 ; i < nLeaders ; i++)
{
unsigned int l = strlen(leaders[i]);
if (strstr(name,leaders[i]) == name &&
strlen(name) > l &&
isupper(name[l]))
{
offset = l;
break;
}
}
return &name[offset];
}
static const char *
stateName(State state)
{
const char *stateName;
switch (state)
{
case sMsgStart:
stateName = "sMsgStart";
break;
case sHalfLineBreakAtMsgStart:
stateName = "sHalfLineBreakAtMsgStart";
break;
case sScanStatusLine:
stateName = "sScanStatusLine";
break;
case sHalfLineBreakAfterStatusLine:
stateName = "sHalfLineBreakAfterStatusLine";
break;
case sAfterLineBreakAfterStatusLine:
stateName = "sAfterLineBreakAfterStatusLine";
break;
case sScanFieldName:
stateName = "sScanFieldName";
break;
case sScanWhitespaceAfter1FieldName:
stateName = "sScanWhitespaceAfter1FieldName";
break;
case sScanWhitespaceAfterNFieldName:
stateName = "sScanWhitespaceAfterNFieldName";
break;
case sScanWhitespaceOr1Value:
stateName = "sScanWhitespaceOr1Value";
break;
case sScanWhitespaceOrNValue:
stateName = "sScanWhitespaceOrNValue";
break;
case sHalfLineBreakInWhitespaceBefore1Value:
stateName = "sHalfLineBreakInWhitespaceBefore1Value";
break;
case sHalfLineBreakInWhitespaceBeforeNValue:
stateName = "sHalfLineBreakInWhitespaceBeforeNValue";
break;
case sAfterLineBreakInWhitespaceBefore1Value:
stateName = "sAfterLineBreakInWhitespaceBefore1Value";
break;
case sAfterLineBreakInWhitespaceBeforeNValue:
stateName = "sAfterLineBreakInWhitespaceBeforeNValue";
break;
case sScan1Value:
stateName = "sScan1Value";
break;
case sScanNValue:
stateName = "sScanNValue";
break;
case sHalfLineBreakIn1Value:
stateName = "sHalfLineBreakIn1Value";
break;
case sHalfLineBreakInNValue:
stateName = "sHalfLineBreakInNValue";
break;
case sAfterLineBreakIn1Value:
stateName = "sAfterLineBreakIn1Value";
break;
case sAfterLineBreakInNValue:
stateName = "sAfterLineBreakInNValue";
break;
case sScanNValueInQuotes:
stateName = "sScanNValueInQuotes";
break;
case sAfterEscCharInQuotesInNValue:
stateName = "sAfterEscCharInQuotesInNValue";
break;
case sHalfLineBreakInQuotesInNValue:
stateName = "sHalfLineBreakInQuotesInNValue";
break;
case sAfterLineBreakInQuotesInNValue:
stateName = "sAfterLineBreakInQuotesInNValue";
break;
case sScanNValueInAngles:
stateName = "sScanNValueInAngles";
break;
case sHalfLineBreakInAnglesInNValue:
stateName = "sHalfLineBreakInAnglesInNValue";
break;
case sAfterLineBreakInAnglesInNValue:
stateName = "sAfterLineBreakInAnglesInNValue";
break;
case sHalfLineBreakAfterLineBreak:
stateName = "sHalfLineBreakAfterLineBreak";
break;
default:
stateName = "<unknown>";
}//switch
return stateName;
}
static const char *
trActionName(TransitionAction transitionAction)
{
const char *transitionActionName;
switch (transitionAction)
{
case taNone:
transitionActionName = "taNone";
break;
case taTermStatusLine:
transitionActionName = "taTermStatusLine";
break;
case taTermFieldName:
transitionActionName = "taTermFieldName";
break;
case taBeyondEmptyValue:
transitionActionName = "taBeyondEmptyValue";
break;
case taTermValueAfterLineBreak:
transitionActionName = "taTermValueAfterLineBreak";
break;
case taTermValue:
transitionActionName = "taTermValue";
break;
case taStartText:
transitionActionName = "taStartText";
break;
case taEndHeader:
transitionActionName = "taEndHeader";
break;
case taChunkTermSentinel:
transitionActionName = "taChunkTermSentinel";
break;
case taError:
transitionActionName = "taError";
break;
default:
transitionActionName = "<unknown>";
}
return transitionActionName;
}
static void
printStateTransition(State state,
char character,
TransitionAction transitionAction)
{
printf(" %s['", cleanName(stateName(state)));
printText(&character, 1);
printf("']: %s\n", cleanName(trActionName(transitionAction)));
}
#if !defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
static const char* stateName(const char*)
{ return "RECOMPILE_WITH_SCANNER_DEBUG"; }
static const char* trActionName(const char*)
{ return stateName(0); }
#endif
/// START OF MEMBER METHODS
int
MsgHeaderScanner::dumpStateMachine(int fd)
{
FILE *fp = fdopen(fd,"w");
if (!fp)
{
fprintf(stderr,"MsgHeaderScanner:: unable to open output file\n");
return -1;
}
// Force instance so things are initialized -- YUCK!
MsgHeaderScanner scanner;(void)scanner;
fprintf(fp,"digraph MsgHeaderScannerFSM {\n");
fprintf(fp,"\tnode[shape=record\n\t\tfontsize=8\n\t\tfontname=\"Helvetica\"\n\t]\n");
fprintf(fp,"\tedge [ fontsize=6 fontname=\"Helvetica\"]\n");
fprintf(fp,"\tgraph [ ratio=0.8\n\t\tfontsize=6 compound=true ]");
for(int state = 0 ; state < numStates; ++state)
{
fprintf(fp,
" %s [ label = \"%d|%s\" ]\n",
cleanName(stateName(state)),
state,
cleanName(stateName(state))
);
for(int category = 0 ; category < numCharCategories; ++category)
{
// Skip Verbose Error or Empty Transitions
if (stateMachine[state][category].nextState == state &&
(stateMachine[state][category].action == taError ||
stateMachine[state][category].action == taNone
)) continue;
fprintf(fp,
" %s -> %s [label=\"%s\\n%s\" ]\n",
cleanName(stateName(state)),
cleanName(stateName(stateMachine[state][category].nextState)),
categorySymbol(category),
cleanName(trActionName(stateMachine[state][category].action)));
}
fprintf(fp,"\n");
}
fprintf(fp,"}\n");
return 0;
}
#endif //defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
static const char *const multiValuedFieldNameArray[] = {
"allow-events",
"accept-encoding",
"accept-language",
"allow",
"content-language",
"proxy-require",
"require",
"supported",
"subscription-state",
"unsupported",
"security-client",
"security-server",
"security-verify",
"accept",
"call-info",
"alert-info",
"error-info",
"record-route",
"route",
"contact",
"authorization",
"proxy-authenticate",
"proxy-authorization",
"www-authenticate",
"via",
0
};
extern
void
lookupMsgHeaderFieldInfo(
char * fieldName, //inout
unsigned int *fieldNameLength, //inout
MsgHeaderScanner::TextPropBitMask fieldNameTextPropBitMask,
int *fieldKind, //out
bool *isMultiValueAllowed) //out
{
*isMultiValueAllowed = false;
const char *const *multiValuedFieldNamePtr = multiValuedFieldNameArray;
for (;;)
{
const char *multiValuedFieldName = *multiValuedFieldNamePtr;
if (!multiValuedFieldName)
{
break;
}
if (strncmp(fieldName, multiValuedFieldName, *fieldNameLength) == 0)
{
*isMultiValueAllowed = true;
break;
}
++multiValuedFieldNamePtr;
}//for
}
static
bool
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -