/* Cfour (C++ Common Console Classes) CgiParser
 * Copyright (C)2001, (C)2002 Jeffrey Bakker

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *  Author:              Jeffrey Bakker <jefskey@yahoo.com>
 *  Filename:            cgiparser.cpp
 *  File version:        1.0.0
 *
 *  REMARK ====================================================================
 *  ===========================================================================
 *
 *  This is the definition file for the CgiParser class.
 *  CgiParser is a Cgi parser library written in C++, which
 *  can be used as a stream class, thanks to operator
 *  overloading. The documentation below will show
 *  how to use the methods.
 *
 *  CHANGELOG =================================================================
 *  ===========================================================================
 *
 *  Created on:         October 10th, 2002
 *
 *  Last Modified on:   November 14th, 2002
 *
 *      - This parser is now complete.
 *      - Added method documentation.
 *
 *
 *  METHOD DOCUMENTATION ======================================================
 *  ===========================================================================
 *
 *  CgiParser& operator<<(string name):
 *
 *   Description: Prints the value of name from form data. If no value exists,
 *                just print the string.
 *
 *  ===========================================================================
 *
 *  CgiParser& operator>>(string &name):
 *
 *   Description: Replace name with the value from the paired form data.
 *
 *  ===========================================================================
 *
 *  CgiParser():
 *
 *   Description: Default constructor. This automatically calls methods that
 *                decodes the data. It also checks validity for REQUEST_METHOD
 *                environment variable.
 *
 *  ===========================================================================
 *
 *  bool is_empty():
 *
 *   Description: Checks to see is there was any form data submitted.
 *
 *
 *   Output:
 *    - returns true if any form data is present, false otherwise.
 *
 *  ===========================================================================
 *
 *  string get_value(string name):
 *
 *   Description: Returns the value of the name from the paired form data.
 *
 *   Input:
 *
 *    Parameter 1
 *    - Name:        name
 *    - Type:        string
 *    - Description: the name of the value
 *
 *   Output:
 *    - returns the value of the name
 *
 *  ===========================================================================
 *
 *  void print_error(string error, string message):
 *
 *   Description: Prints an error message to the browser.
 *
 *   Input:
 *
 *    Parameter 1
 *    - Name:        error
 *    - Type:        string
 *    - Description: the error code, or the title
 *
 *    Parameter 2
 *    - Name:        message
 *    - Type:        string
 *    - Description: a more detailed description of the error
 *
 *  ===========================================================================
 *
 *  The following methods shall *never* be called by the programmer. They are
 *  all automatically called the moment the constructor is called. The methods
 *  are for URL decoding. Using these methods manually may cause undesired
 *  results, therefore there will be no ducumentation on how to use them.
 *
 *      bool	InitData()              // top level, calls the others
 *      void	get_query()             // get data from GET method
 *      void	get_stdin()             // get data from POST method
 *      void	parse_spaces()          // convert '+' into ' '
 *      void	split_data()            // split form data into pairs
 *      void	decode_hex(string&)     // do URL decoding
 *      inline	char asmhex(char)       // convert hexadecimal
 *
 *  END METHOD DOCUMENTATION ==================================================
 *  ===========================================================================
 * _______. ..
 */

#include "cgiparser.h" 

// construction ---------------------------------------------------------------
CgiParser::CgiParser() {

	if(DEBUG_CGI_TRACE)
	cout << "Content-type: text/plain\n\nIn Constructor\n";

	first_print = true;
	QStr = "";

	// Automatically decode form data
	// when CgiParser object is created

	if(!InitData()) {
		print_error("Invalid Request Method","");
	}
}

// initialize form data to be decoded -----------------------------------------
bool	CgiParser::InitData() {

	if(DEBUG_CGI_TRACE)
	cout << "In InitData()\n";

	string Method;

        // get the request method: GET or POST ?
	Method = getenv("REQUEST_METHOD");

	if(Method ==  "GET")	{get_query();}

	else

	if(Method == "POST")	{get_stdin();}

	else return false;

	parse_spaces();  // convert '+' to ' '
	split_data();    // split name=value&name=value into data pairs

	if(DEBUG_CGI_TRACE)
	cout << "In InitData()\n";

	return true;
}

// get url-friendly query from GET --------------------------------------------
void	CgiParser::get_query() {

	QStr = getenv("QUERY_STRING");
}

// get url-friendly stdin from POST -------------------------------------------
void	CgiParser::get_stdin() {

	if(DEBUG_CGI_TRACE) cout << "in get_stdin() point 1\n";

	int	Length;
	string	chars_long;

	// know how much bytes are to be read from STDIN

	chars_long	= getenv("CONTENT_LENGTH");
	Length		= atoi(chars_long.data());

//	char	StdIn[Length+1];  // create a buffer for the incoming post data
	char*	StdIn = new char[Length+1];

	if(DEBUG_CGI_TRACE)
        cout << "in get_stdin() point 2 Length: " << Length << "\n";

	// read the post data from STDIN for Length + 1 amount of bytes
	cin.get(StdIn,Length+1);
	QStr = StdIn;

	if(DEBUG_CGI_TRACE) cout << "Post  data is: " <<  QStr << endl;
	if(DEBUG_CGI_TRACE) cout << "leaving get_stdin()\n";

	delete [] StdIn;
}

// convert all instances of '+' into a space ----------------------------------
void	CgiParser::parse_spaces() {

	if(DEBUG_CGI_TRACE) cout << "in parse_spaces()\n";

        for(int i = 0; i < QStr.size(); i++)
        {
                if(QStr[i] == '+') {QStr[i] = ' ';}
        }

	if(DEBUG_CGI_TRACE) cout << QStr << endl;
}

// decode the hex escapes in the url encoded string ---------------------------
void	CgiParser::decode_hex(string &data) {

	if(DEBUG_CGI_TRACE) cout << "in decode_hex()\n";

	char	one,two;
	int	index = 0;
	bool	finished = false;

	index = data.find("%",index);

	while(!finished || index < string::npos) {

		if(index != -1) {

			one = asmhex(data[index+1]);
			two = asmhex(data[index+2]);
			one *= 0x10;

			data.erase(index,2);
                        data[index] = (char)one+two;

			index++;
			index = data.find("%",index);
		}
		else finished = true;
	}

	if(DEBUG_CGI_TRACE) cout << data << endl;
}

// translate single hex char to hex digit (using inline assembly) -------------
inline	char CgiParser::asmhex(char hex) {

/*
	if( hex >= (char) 0x41 ) {

		asm( "AND $0xdf,%0" : "=r" (hex) );
		asm( "SUB $0x41,%0" : "=r" (hex) );
		asm( "ADD $0x0a,%0" : "=r" (hex) );

	} else {

		asm( "SUB $0x30,%0" : "=r" (hex) );
	}

	return hex;
*/

        if(hex >= 0x41) {return ((hex & 0xdf) -0x41) + 0x0a;}
        else            {return hex - 0x30;}
}

//  split up everything between the &'s and ='s -------------------------------
void    CgiParser::split_data() {

	if(DEBUG_CGI_TRACE) cout << "in split_data()\n";

        string nm,vl;  // temporary
	DataPair Pair; // data store

	int nidx,vidx; // name = value indexes
	bool finished = false;
        bool last = false;

        nidx = 0;

        vidx = QStr.find("=",nidx);
        if(vidx == -1) {return;}

        while (!finished) {

                nm = QStr.substr(nidx,vidx - nidx);
                if(nm[0] == '&') {
                        nm.erase(0,1);
                }
                decode_hex(nm); // decode the url encoded escapes

        	if(DEBUG_CGI_TRACE) cout << "found name:\t"  << nm << endl;

                nidx = QStr.find("&",vidx);
                if(nidx == -1) {
                        nidx = QStr.size() -1;
                        last = true;
                }

                vl = QStr.substr(vidx+1,nidx - ( (!last)? vidx : vidx-1 ) );
                if(vl[vl.size() -1] == '&') {
                        vl.erase(vl.size() -1,1);
                }
                decode_hex(vl); // decode the url encoded escapes


        	if(DEBUG_CGI_TRACE) cout << "found value:\t" << vl << endl;

                Pair.Name  = nm;
                Pair.Value = vl;

                CgiData.push_back(Pair);

                vidx = QStr.find("=",vidx+1);
                if(vidx == -1) {
                        finished = true;
                }
        }
}

// return the paired value of the give name -----------------------------------
string	CgiParser::get_value(string Name) {

	for(int i=0;i < CgiData.size();i++) {

		if(CgiData[i].Name == Name) {
			return CgiData[i].Value;
		}
	}
	return "\0";  // if the pair doesn't exist
}

// check to see if there was any form data submitted --------------------------
bool	CgiParser::is_empty() {

	return (CgiData.size() == 0) ? true : false; // is there any form data?
}

// print given error message --------------------------------------------------
void	CgiParser::print_error(string error, string msg) {

	cout	<< "Content-type: text/html\n\n"
		<< "<html>\n<head>\n<title>Error</title>\n</head>\n"
		<< "<body>\n\n<H1>Error: " + error + "</H1>\n<br><br>\n";

	if(msg != "") cout << msg << endl;

	cout <<	"\n\n</body>\n</html>";

	exit(0);
}

// print cgi variables by using their names, if !found print the string -------
CgiParser& CgiParser::operator<<(string name) {

	if(first_print) {
		cout << "Content-type: text/html\n\n";
		first_print = false;
	}

	string value;
	value = get_value(name);

	if (value != "\0") {
		cout << value;
	} else {
		cout << name;
	}

	return *this;
}

// swap the value into the string that matches the given name -----------------
CgiParser& CgiParser::operator>>(string &name) {

	name = get_value(name);

	return *this;
}

// end of class implementation ------------------------------------------------




w e b c p p
web c plus plus