Ann : CCard Parser (vCard/vCal)

[email protected] 4 Feb 2003 5:46:46 GMT
Newsgroups gmane.ietf.vcard
Message-ID <[email protected]>
Hi All,



I've been working on a generic card parser in C, that I'm releasing for
general use, its event orientated, and designed to be used in a similar
manner to expat.



Source Download:

Initally from my homepage:



  http://members.optusnet.com.au/~blackpaw/



but I'll move to sourceforge if it proves useful.



Feedback is welcome, except - don't suggest using the GPL.



From the readme:

Licensing : All code is under the Mozilla Public License 1.1 (MPL 1.1) as
specified in 

license.txt



Features:

=========

- generic for any card sytax, e.g vCard & vCal

- reports errors in sytax

- Event orientated (ie reentrant & stream orientated)

- Handles line folding

- Automatic decoding of params

- Handles quoted-printable decoding (base64 due soon)





Does NOT:

---------

- Generate cards (parser *only*)

- verify overall card structure - ie if required properties are missing -
tough.





Vague Documentation

===================



Purpose:

--------

Card parser is for the general parsing of card (doh!) objects, aka vCards &
vCals.

It is a event orientated parser designed to be used in a similar manner to
expat (a XML

parser).



In general:

-----------



1. Create a card parser

   - CARD_ParserCreate



2. Init the parser:

   - CARD_SetUserData

   - CARD_SetPropHandler

   - CARD_SetDataHandler



3. Feed it Data

   - CARD_Parse

   - Handle the parse events in the callbacks specified in 2.

   - Keep feeding it data in as large and small chunks as you like



4. Free the card parser

   - CARD_ParserFree





Sample Test Progam:

===================

#include <iostream>

#include <string>

#include <fstream>

#include <algorithm>

#include <sstream>

using namespace std;



#include "cardparser.h"

#include <assert.h>



#define TOUPPER(s) transform(s.begin(), s.end(), s.begin(), toupper)



///////////////////////////////////////////////

// Test

class TUserData

{

public:

	int indent;

	bool inBegin, inEnd, startData;

	string cardType;



	TUserData() : indent(0), inBegin(false), inEnd(false), startData(true) {}

};



extern "C" void PropHandler(void *userData, const CARD_Char *propName, const
CARD_Char **params)

{

	TUserData *ud = (TUserData *) userData;

	assert(ud != NULL);



	ud->inBegin = false;

	ud->inEnd = false;

	ud->startData = true;



	if (strcmpi(propName, "BEGIN") == 0)

	{

		// begin: vcard/vcal/whatever

		ud->inBegin = true;

		ud->indent++;

	}

	else if (strcmpi(propName, "END") == 0)

	{

		// end: vcard/vcal/whatever

		ud->inEnd = true;

		ud->indent--;

	}

	else

	{

		cout << string(ud->indent * 4, ' ');



		string pname = propName;

		TOUPPER(pname);

		cout << pname << ":" << endl;



		const CARD_Char **p = params;

		while (p[0])

		{

			cout << string(ud->indent * 4, ' ') << " * " << p[0];



			if (p[1])

				cout << "=" << '\"' << p[1] << '\"' ;



			cout << endl;

			p += 2;

		};

	};

};





extern "C" void DataHandler(void *userData, const CARD_Char *data, int len)

{

	TUserData *ud = (TUserData *) userData;

	assert(ud != NULL);



	if (ud->inBegin)

	{

		// accumulate begin data

		ostringstream os;

		if (len > 0)

		{

			os.write(data, len);

			ud->cardType += os.str();

		}

		else

		{

			TOUPPER(ud->cardType);

			cout 

				<< string(ud->indent * 4 - 4, ' ') 

				<< "[" << ud->cardType << "]" << endl;

		};

	}

	else if (ud->inEnd)

	{

		if (len == 0)

			cout << "EOF [" << ud->cardType << "]" << endl;

	}

	else

	{

		if (ud->startData)

			cout << string(ud->indent * 4, ' ') << " Data = {";

		ud->startData = false;



		if (len == 0)

			cout << "}" << endl;

		else

		{

			// output printable data

			for (int i = 0; i < len; i++)

			{

				CARD_Char c = data[i];

				if (c == '\r')

					cout << "\\r";

				else if (c == '\n')

					cout << "\\n";

				else

					cout << c;

			};

		};

	};



	/*

	if (len == 0)

		cout << ":" << endl;

	else

		cout.write(data, len);

		*/

};



int main()

{

	cout << "Test vCard parser" << endl;



	// open test

	ifstream is("test1.vcd", ios::binary);

	if (! is)

	{

		cout << "Unable to open test card <test1.vcd>" << endl;

		return 0;

	};



	// userData

	TUserData userData;



	// allocate parser

	CARD_Parser vp = CARD_ParserCreate(NULL);



	// initialise

	CARD_SetUserData(vp, &userData);

	CARD_SetPropHandler(vp, PropHandler);

	CARD_SetDataHandler(vp, DataHandler);



	// parse

	bool parseErr = false;

	char buf[512];

	is.read(buf, sizeof(buf));

	while (is.gcount() > 0)

	{

		int len = is.gcount();

		int rc = CARD_Parse(vp, buf, len, false);

		if (rc == 0)

		{

			parseErr = true;

			cout << "Error parsing vcard" << endl;

			break;

		};



		is.read(buf, sizeof(buf));

	};



	// finalise parsing

	if (! parseErr)

		CARD_Parse(vp, NULL, 0, true);



	// free parser

	CARD_ParserFree(vp);



	// done

	cout << "Done." << endl;



	return 0;

};





Thanks - Lindsay