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