Files

759 lines
23 KiB
C

#include "type.h"
#include <string.h>
#include <stdio.h>
//*****************************************************************************
//
// Searches the list of parameters passed to a CGI handler and returns the
// index of a given parameter within that list.
//
// \param pcToFind is a pointer to a string containing the name of the
// parameter that is to be found.
// \param pcParam is an array of character pointers, each containing the name
// of a single parameter as encoded in the URI requesting the CGI.
// \param iNumParams is the number of elements in the pcParam array.
//
// This function searches an array of parameters to find the string passed in
// \e pcToFind. If the string is found, the index of that string within the
// \e pcParam array is returned, otherwise -1 is returned.
//
// \return Returns the index of string \e pcToFind within array \e pcParam
// or -1 if the string does not exist in the array.
//
//*****************************************************************************
int FindCGIParameter(const char *pcToFind, char *pcParam[], int iNumParams)
{
int iLoop;
//
// Scan through all the parameters in the array.
//
for(iLoop = 0; iLoop < iNumParams; iLoop++)
{
//
// Does the parameter name match the provided string?
//
if(strcmp(pcToFind, pcParam[iLoop]) == 0)
{
//
// We found a match - return the index.
//
return(iLoop);
}
}
//
// If we drop out, the parameter was not found.
//
return(-1);
}
//*****************************************************************************
//
// Determines whether a given character is a valid hexadecimal digit.
//
// \param cDigit is the ASCII character code to be checked for validity.
//
// This function checks the passed character to determime whether or not it is
// a valid hexadecimal digit.
//
// \return Returns \e true if the passed character is a valid hex digit or \e
// false otherwise
//
//*****************************************************************************
tBoolean IsValidHexDigit(const char cDigit)
{
if(((cDigit >= '0') && (cDigit <= '9')) ||
((cDigit >= 'a') && (cDigit <= 'f')) ||
((cDigit >= 'A') && (cDigit <= 'F')))
{
return(true);
}
else
{
return(false);
}
}
//*****************************************************************************
//
// Converts an ASCII character to a hex digit value.
//
// \param cDigit is the ASCII character code to convert to a number.
//
// This function converts a passed ASCII character to a number assuming that
// the character is a valid hexadecimal digit. If the character is not a valid
// hex digit, the value 0xFF is returned.
//
// \return Returns the number represented by hex digit \e cDigit or 0xFF if
// the character passed is not valid hex.
//
//*****************************************************************************
unsigned char HexDigit(const char cDigit)
{
if((cDigit >= '0') && (cDigit <= '9'))
{
return(cDigit - '0');
}
else
{
if((cDigit >= 'a') && (cDigit <= 'f'))
{
return((cDigit - 'a') + 10);
}
else
{
if((cDigit >= 'A') && (cDigit <= 'F'))
{
return((cDigit - 'A') + 10);
}
}
}
//
// If we get here, we were passed an invalid hex digit so return 0xFF.
//
return(0xFF);
}
//*****************************************************************************
//
// Decodes a single %xx escape sequence as an ASCII character.
//
// \param pcEncoded points to the ``%'' character at the start of a three
// character escape sequence which represents a single ASCII character.
// \param pcDecoded points to a byte which will be written with the decoded
// character assuming the escape sequence is valid.
//
// This function decodes a single escape sequence of the form ``%xy'' where
// x and y represent hexadecimal digits. If each digit is a valid hex digit,
// the function writes the decoded character to the pcDecoded buffer and
// returns true, else it returns false.
//
// \return Returns \b true on success or \b false if pcEncoded does not point
// to a valid escape sequence.
//
//*****************************************************************************
tBoolean DecodeHexEscape(const char *pcEncoded, char *pcDecoded)
{
if((pcEncoded[0] != '%') || !IsValidHexDigit(pcEncoded[1]) ||
!IsValidHexDigit(pcEncoded[2]))
{
return(false);
}
else
{
*pcDecoded = ((HexDigit(pcEncoded[1]) * 16) +
HexDigit(pcEncoded[2]));
return(true);
}
}
//*****************************************************************************
//
// Encodes a string for use within an HTML tag, escaping non alphanumeric
// characters.
//
// \param pcDecoded is a pointer to a null terminated ASCII string.
// \param pcEncoded is a pointer to a storage for the encoded string.
// \param ulLen is the number of bytes of storage pointed to by pcEncoded.
//
// This function encodes a string, adding escapes in place of any special,
// non-alphanumeric characters. If the encoded string is too long for the
// provided output buffer, the output will be truncated.
//
// \return Returns the number of characters written to the output buffer
// not including the terminating NULL.
//
//*****************************************************************************
unsigned long
EncodeFormString(const char *pcDecoded, char *pcEncoded,
unsigned long ulLen)
{
unsigned long ulLoop;
unsigned long ulCount;
//
// Make sure we were not passed a tiny buffer.
//
if(ulLen <= 1)
{
return(0);
}
//
// Initialize our output character counter.
//
ulCount = 0;
//
// Step through each character of the input until we run out of data or
// space to put our output in.
//
for(ulLoop = 0; pcDecoded[ulLoop] && (ulCount < (ulLen - 1)); ulLoop++)
{
switch(pcDecoded[ulLoop])
{
//
// Pass most characters without modification.
//
default:
{
pcEncoded[ulCount++] = pcDecoded[ulLoop];
break;
}
case '\'':
{
ulCount += snprintf(&pcEncoded[ulCount], (ulLen - ulCount),
"&#39;");
break;
}
}
}
return(ulCount);
}
//*****************************************************************************
//
// Decodes a string encoded as part of an HTTP URI.
//
// \param pcEncoded is a pointer to a null terminated string encoded as per
// RFC1738, section 2.2.
// \param pcDecoded is a pointer to storage for the decoded, null terminated
// string.
// \param ulLen is the number of bytes of storage pointed to by pcDecoded.
//
// This function decodes a string which has been encoded using the method
// described in RFC1738, section 2.2 for URLs. If the decoded string is too
// long for the provided output buffer, the output will be truncated.
//
// \return Returns the number of character written to the output buffer, not
// including the terminating NULL.
//
//*****************************************************************************
unsigned long
DecodeFormString(const char *pcEncoded, char *pcDecoded,
unsigned long ulLen,int ign_quotation)
{
unsigned long ulLoop;
unsigned long ulCount;
tBoolean bValid;
ulCount = 0;
ulLoop = 0;
//
// Keep going until we run out of input or fill the output buffer.
//
while(pcEncoded[ulLoop] && (ulCount < (ulLen - 1)))
{
switch(pcEncoded[ulLoop])
{
//
// '+' in the encoded data is decoded as a space.
//
case '+':
{
pcDecoded[ulCount++] = ' ';
ulLoop++;
break;
}
//
// '%' in the encoded data indicates that the following 2
// characters indicate the hex ASCII code of the decoded character.
//
case '%':
{
if(pcEncoded[ulLoop + 1] && pcEncoded[ulLoop + 2])
{
//
// Decode the escape sequence.
//
bValid = DecodeHexEscape(&pcEncoded[ulLoop],
&pcDecoded[ulCount]);
//
// If the escape sequence was valid, move to the next
// output character.
//
if(ign_quotation)//用户提交 " 字符,忽略,不做处理
{
if(pcDecoded[ulCount]=='"')
{
pcDecoded[ulCount]=' ';
}
}
if(bValid)
{
ulCount++;
}
//
// Skip past the escape sequence in the encoded string.
//
ulLoop += 3;
}
else
{
//
// We reached the end of the string partway through an
// escape sequence so just ignore it and return the number
// of decoded characters found so far.
//
pcDecoded[ulCount] = '\0';
return(ulCount);
}
break;
}
case '"': //用户提交"" 字符,忽略,不做处理
if(ign_quotation)
{
pcDecoded[ulCount++] = ' ';
ulLoop++;
}
else
{
pcDecoded[ulCount++] = pcEncoded[ulLoop++];
}
break;
//
// For all other characters, just copy the input to the output.
//
default:
{
pcDecoded[ulCount++] = pcEncoded[ulLoop++];
break;
}
}
}
//
// Terminate the string and return the number of characters we decoded.
//
pcDecoded[ulCount] = '\0';
return(ulCount);
}
//*****************************************************************************
//
// Ensures that a string passed represents a valid decimal number and,
// if so, converts that number to a long.
//
// \param pcValue points to a null terminated string which should contain an
// ASCII representation of a decimal number.
// \param plValue points to storage which will receive the number represented
// by pcValue assuming the string is a valid decimal number.
//
// This function determines whether or not a given string represents a valid
// decimal number and, if it does, converts the string into a decimal number
// which is returned to the caller.
//
// \return Returns \b true if the string is a valid representation of a
// decimal number or \b false if not.
//*****************************************************************************
tBoolean
CheckDecimalParam(const char *pcValue, long *plValue)
{
unsigned long ulLoop;
tBoolean bStarted;
tBoolean bFinished;
tBoolean bNeg;
long lAccum;
//
// Check that the string is a valid decimal number.
//
bStarted = false;
bFinished = false;
bNeg = false;
ulLoop = 0;
lAccum = 0;
while(pcValue[ulLoop])
{
//
// Ignore whitespace before the string.
//
if(!bStarted)
{
if((pcValue[ulLoop] == ' ') || (pcValue[ulLoop] == '\t'))
{
ulLoop ++;
continue;
}
//
// Ignore a + or - character as long as we have not started.
//
if((pcValue[ulLoop] == '+') || (pcValue[ulLoop] == '-'))
{
//
// If the string starts with a '-', remember to negate the
// result.
//
bNeg = (pcValue[ulLoop] == '-') ? true : false;
bStarted = true;
ulLoop++;
}
else
{
//
// We found something other than whitespace or a sign character
// so we start looking for numerals now.
//
bStarted = true;
}
}
if(bStarted)
{
if(!bFinished)
{
//
// We expect to see nothing other than valid digit characters
// here.
//
if((pcValue[ulLoop] >= '0') && (pcValue[ulLoop] <= '9'))
{
lAccum = (lAccum * 10) + (pcValue[ulLoop] - '0');
}
else
{
//
// Have we hit whitespace? If so, check for no more
// characters until the end of the string.
//
if((pcValue[ulLoop] == ' ') || (pcValue[ulLoop] == '\t'))
{
bFinished = true;
}
else
{
//
// We got something other than a digit or whitespace so
// this makes the string invalid as a decimal number.
//
return(false);
}
}
}
else
{
//
// We are scanning for whitespace until the end of the string.
//
if((pcValue[ulLoop] != ' ') && (pcValue[ulLoop] != '\t'))
{
//
// We found something other than whitespace so the string
// is not valid.
//
return(false);
}
}
//
// Move on to the next character in the string.
//
ulLoop++;
}
}
//
// If we drop out of the loop, the string must be valid. All we need to do
// now is negate the accumulated value if the string started with a '-'.
//
*plValue = bNeg ? -lAccum : lAccum;
return(true);
}
void CheckStringParam(const char *pcValue, char *pbuf)
{
unsigned long ulLoop;
tBoolean bStarted;
// Check that the string is a valid string.
bStarted = false;
ulLoop = 0;
while(pcValue[ulLoop])
{
// Ignore whitespace before the string.
if(!bStarted)
{
if((pcValue[ulLoop] == ' ') || (pcValue[ulLoop] == '\t')|| (pcValue[ulLoop] == '\"'))
{
ulLoop ++;
continue;
}
bStarted = true;
}
if(bStarted)
{
if((pcValue[ulLoop] == '\t')|| (pcValue[ulLoop] == '\"')||(pcValue[ulLoop] == '\0'))
{
*pbuf = 0;
return;
}
else
{
*pbuf++ = pcValue[ulLoop];
}
ulLoop++;
}
}
*pbuf = 0;
return;
}
//*****************************************************************************
//
// Searches the list of parameters passed to a CGI handler for a parameter
// with the given name and, if found, reads the parameter value as a decimal
// number.
//
// \param pcName is a pointer to a string containing the name of the
// parameter that is to be found.
// \param pcParam is an array of character pointers, each containing the name
// of a single parameter as encoded in the URI requesting the CGI.
// \param iNumParams is the number of elements in the pcParam array.
// \param pcValues is an array of values associated with each parameter from
// the pcParam array.
// \param pbError is a pointer that will be written to \b true if there is any
// error during the parameter parsing process (parameter not found, value is
// not a valid decimal number).
//
// This function searches an array of parameters to find the string passed in
// \e pcName. If the string is found, the corresponding parameter value is
// read from array pcValues and checked to make sure that it is a valid
// decimal number. If so, the number is returned. If any error is detected,
// parameter \e pbError is written to \b true. Note that \e pbError is NOT
// written if the parameter is successfully found and validated. This is to
// allow multiple parameters to be parsed without the caller needing to check
// return codes after each individual call.
//
// \return Returns the value of the parameter or 0 if an error is detected (in
// which case \e *pbError will be \b true).
//
//*****************************************************************************
long
GetCGIParam(const char *pcName, char *pcParams[], char *pcValue[],
int iNumParams, tBoolean *pbError)
{
int iParam;
long lValue;
tBoolean bRetcode;
//
// Is the parameter we are looking for in the list?
//
*pbError = false;
iParam = FindCGIParameter(pcName, pcParams, iNumParams);
if(iParam != -1)
{
//
// We found the parameter so now get its value.
//
bRetcode = CheckDecimalParam(pcValue[iParam], &lValue);
if(bRetcode)
{
//
// All is well - return the parameter value.
//
return(lValue);
}
}
//
// If we reach here, there was a problem so return 0 and set the error
// flag.
//
*pbError = true;
return(0);
}
long GetCGIStringParam(const char *pcName, char *pcParams[], char *pcValue[],
int iNumParams,char *pbuf,int buflen,int ign_quotation)
{
int iParam;
// Is the parameter we are looking for in the list?
iParam = FindCGIParameter(pcName, pcParams, iNumParams);
if(iParam != -1)
{
// We found the parameter so now get its value.
//CheckStringParam(pcValue[iParam], pbuf);
return DecodeFormString(pcValue[iParam], pbuf,buflen,ign_quotation);
}
else
{
return 0;
}
}
tBoolean
CheckHexParam(const char *pcValue, long *plValue)
{
unsigned long ulLoop;
tBoolean bStarted;
tBoolean bFinished;
tBoolean bNeg;
long lAccum;
//
// Check that the string is a valid HEX number.
//
bStarted = false;
bFinished = false;
bNeg = false;
ulLoop = 0;
lAccum = 0;
while(pcValue[ulLoop])
{
//
// Ignore whitespace before the string.
//
if(!bStarted)
{
if((pcValue[ulLoop] == ' ') || (pcValue[ulLoop] == '\t')|| (pcValue[ulLoop] == '\"'))
{
ulLoop ++;
continue;
}
//
// Ignore a + or - character as long as we have not started.
//
if((pcValue[ulLoop] == '+') || (pcValue[ulLoop] == '-'))
{
//
// If the string starts with a '-', remember to negate the
// result.
//
bNeg = (pcValue[ulLoop] == '-') ? true : false;
bStarted = true;
ulLoop++;
}
else
{
//
// We found something other than whitespace or a sign character
// so we start looking for numerals now.
//
bStarted = true;
}
}
if(bStarted)
{
if(!bFinished)
{
//
// We expect to see nothing other than valid digit characters
// here.
//
if((pcValue[ulLoop] >= '0') && (pcValue[ulLoop] <= '9'))
{
lAccum = (lAccum * 16) + (pcValue[ulLoop] - '0');
}
else if((pcValue[ulLoop] >= 'A') && (pcValue[ulLoop] <= 'F'))
{
lAccum = (lAccum * 16) + (pcValue[ulLoop]+ 10 - 'A');
}
else if((pcValue[ulLoop] >= 'a') && (pcValue[ulLoop] <= 'f'))
{
lAccum = (lAccum * 16) + (pcValue[ulLoop]+ 10 - 'a');
}
else
{
//
// Have we hit whitespace? If so, check for no more
// characters until the end of the string.
//
if((pcValue[ulLoop] == ' ') || (pcValue[ulLoop] == '\t')|| (pcValue[ulLoop] == '\"'))
{
bFinished = true;
}
else
{
//
// We got something other than a digit or whitespace so
// this makes the string invalid as a decimal number.
//
return(false);
}
}
}
else
{
//
// We are scanning for whitespace until the end of the string.
//
if((pcValue[ulLoop] != ' ') && (pcValue[ulLoop] != '\t')|| (pcValue[ulLoop] == '\"'))
{
//
// We found something other than whitespace so the string
// is not valid.
//
return(false);
}
}
//
// Move on to the next character in the string.
//
ulLoop++;
}
}
//
// If we drop out of the loop, the string must be valid. All we need to do
// now is negate the accumulated value if the string started with a '-'.
//
*plValue = bNeg ? -lAccum : lAccum;
return(true);
}
long
GetCGIHexParam(const char *pcName, char *pcParams[], char *pcValue[],
int iNumParams, tBoolean *pbError)
{
int iParam;
long lValue;
tBoolean bRetcode;
*pbError = false;
//
// Is the parameter we are looking for in the list?
//
iParam = FindCGIParameter(pcName, pcParams, iNumParams);
if(iParam != -1)
{
//
// We found the parameter so now get its value.
//
bRetcode = CheckHexParam(pcValue[iParam], &lValue);
if(bRetcode)
{
//
// All is well - return the parameter value.
//
return(lValue);
}
}
//
// If we reach here, there was a problem so return 0 and set the error
// flag.
//
*pbError = true;
return(0);
}