|
|
//
// MODULE: APGTSQRY.CPP
//
// PURPOSE: Implementation file for PTS Query Parser
// Fully implements class CHttpQuery, parsing out NAME=VALUE pairs from HTTP query string
//
// PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint
//
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
//
// AUTHOR: Roman Mach
//
// ORIGINAL DATE: 8-2-96
//
// NOTES:
// 1. Based on Print Troubleshooter DLL
// 2. Caller is responsible to assure that all buffers passed in are large enough
//
// Version Date By Comments
//--------------------------------------------------------------------
// V0.1 - RM Original
// V3.1 12/17/98 JM Major cleanup, add Push capablity
//
#pragma warning(disable:4786)
#include "stdafx.h"
#include "apgts.h"
#include "apgtscls.h"
//
//
CHttpQuery::CHttpQuery() : m_state(ST_GETDATA), m_nIndex(0) { }
//
//
CHttpQuery::~CHttpQuery() { }
//
// INPUT *szInput - this is the URL-encoded query string in which we are searching
// INPUT *pchName - must point to a buffer of size MAXBUF
// OUTPUT *pchName - Typically NAME of a NAME=VALUE pair. Any URL-encoding stripped out.
// Null-terminated. Leading and trailing blanks stripped.
// INPUT *pchValue - must point to a buffer of size MAXBUF
// OUTPUT *pchValue - Typically VALUE of a NAME=VALUE pair. Any URL-encoding stripped out.
// Null-terminated. Leading and trailing blanks stripped.
// RETURN - TRUE ==> more data to come
BOOL CHttpQuery::GetFirst(LPCTSTR szInput, TCHAR *pchName, TCHAR *pchValue) { m_state = ST_GETDATA; m_strInput = szInput; m_nIndex = 0; BOOL status = LoopFind(pchName, pchValue); CleanStr(pchName); CleanStr(pchValue); return (status); }
// Called after a call to CHttpQuery::GetFirst or to this fn has returned true
// INPUT *pchName - must point to a buffer of size MAXBUF
// OUTPUT *pchName - Typically NAME of a NAME=VALUE pair
// Null-terminated. Leading and trailing blanks stripped.
// INPUT *pchValue - must point to a buffer of size MAXBUF
// OUTPUT *pchValue - Typically VALUE of a NAME=VALUE pair
// Null-terminated. Leading and trailing blanks stripped.
// RETURN - TRUE ==> more data to come
BOOL CHttpQuery::GetNext(TCHAR *pchName, TCHAR *pchValue) { BOOL status = LoopFind(pchName, pchValue); CleanStr(pchName); CleanStr(pchValue); return (status); }
// put new content on the front of the unparsed portion of the query string in which we are
// searching.
// Typically, szPushed should consist of 1 or more NAME=VALUE pairs, each terminated by an
// ampersand ("&").
void CHttpQuery::Push(LPCTSTR szPushed) { m_state = ST_GETDATA; m_strInput = CString(szPushed) + m_strInput.Mid(m_nIndex); m_nIndex = 0; }
//
// RETURN - TRUE ==> more data to come
// INPUT *pchName - must point to a buffer of size MAXBUF
// OUTPUT *pchName - Typically NAME of a NAME=VALUE pair. Any URL-encoding stripped out.
// Null-terminated. May have leading and/or trailing blanks
// INPUT *pchValue - must point to a buffer of size MAXBUF
// OUTPUT *pchValue - Typically VALUE of a NAME=VALUE pair. Any URL-encoding stripped out.
// Null-terminated. May have leading and/or trailing blanks
BOOL CHttpQuery::LoopFind(TCHAR *pchName, TCHAR *pchValue) { *pchName = NULL; *pchValue = NULL;
TCHAR ch; int val, oldval = 0; TCHAR temp[20]; // a way bigger buffer than we need
TCHAR *pchPut; // initially points to pchName but can change to point to pchValue
int nLength = m_strInput.GetLength();
if (m_nIndex >= nLength) return (FALSE);
pchPut = pchName; while (m_nIndex < nLength) { ch = m_strInput[m_nIndex++]; // You might think something related to _tcsinc()
// would be called for to advance m_nIndex. You'd be wrong,
// although the choice would be harmless.
// URL-encoding keeps us within the ASCII character set, so no double-
// byte issues should arise. Besides that, the strings passed in to the
// command line of the troubleshooter controls are even further
// constrained: for example, even in a Japanese-language topic, node
// names will be ASCII.
switch(m_state) { case ST_GETDATA: if (ch == _T('&')) // expect another NAME=VALUE pair
return (TRUE); else if (ch == _T('=')) { // Got a name, expect a value
pchPut = pchValue; break; } else if (ch == _T('%')) // expect to be followed by 2-digit hex
m_state = ST_DECODEHEX1; else if (ch == _T('+')) // encoded blank
AddBuffer(_T(' '),pchPut); else AddBuffer(ch,pchPut); break; case ST_DECODEHEX1: // first of 2 hex digits
temp[0] = ch; m_state = ST_DECODEHEX2; break; case ST_DECODEHEX2: // second of 2 hex digits; parse it into a hex value & affix it to *pchPut
temp[1] = ch; temp[2] = 0; _stscanf(temp,_T("%02X"),&val);
// reinterpret CR, LF, or CRLF as '\n'
if (val == 0x0A) { if (oldval != 0x0D) AddBuffer(_T('\n'),pchPut); } else if (val == 0x0D) AddBuffer(_T('\n'),pchPut); else AddBuffer( static_cast<TCHAR>(val), pchPut );
oldval = val; m_state = ST_GETDATA; break; default: return (FALSE); } } return (TRUE); }
//
// append ch to *tostr, with a few subtleties: see comments in body of routine
void CHttpQuery::AddBuffer( TCHAR ch, TCHAR *tostr) { if (ch == _T('\t')) // TAB -> 4 blanks
PutStr(_T(" "),tostr); else if (ch == _T('\n')) // blank before newline
PutStr(_T(" \n"),tostr); else if (ch == _T('<')) // html: must encrypt left angle bracket.
PutStr(_T("<"),tostr); else if (ch == _T('>')) // html: must encrypt right angle bracket.
PutStr(_T(">"),tostr); else if (ch > 0x7E || ch < 0x20) // refuse DEL, NUL, and control characters
return; else { TCHAR temp[2]; temp[0] = ch; temp[1] = _T('\0'); PutStr(temp,tostr); } }
// append string *addtostr to string *instr up to a maximum size of MAXBUF-1
// INPUT/OUTPUT *instr
// INPUT *addtostr
// NOTE that this fails silently if total lengths exceed MAXBUF-1 chars
void CHttpQuery::PutStr(LPCTSTR instr, TCHAR *addtostr) { if ((_tcslen(instr)+_tcslen(addtostr)) >= (MAXBUF-1)) { // can't add it to buff
return; } _tcscat(addtostr,instr); }
// Acts upon INPUT/OUTPUT *str - strip any leading control characters and spaces,
// turn any other control characters and spaces into '\0's
/* static */ void CHttpQuery::CleanStr(TCHAR *str) { TCHAR temp[MAXBUF], *ptr; int len;
ptr = str; while (*ptr > _T('\0') && *ptr <= _T(' ')) ptr = _tcsinc(ptr); _tcscpy(temp,ptr); if ((len = _tcslen(temp))!=0) { ptr = &temp[len-1]; while (ptr > temp) { if (*ptr > _T('\0') && *ptr <= _T(' ')) *ptr = _T('\0'); else break; ptr = _tcsdec(temp, ptr); } } _tcscpy(str,temp); }
|