Header parser iterator

The x::mime::header_iter template instantiates an output iterator that takes the output sequence from x::mime::bodystart_iter. The template parameter is another output iterator class, over an int output sequence. Instantiated by create(), the constructor takes an instance of the output iterator class, which ends up iterating over the output sequence that x::mime::header_iter received, and x::mime::header_iter adds additional values into the output sequence:

#include <x/mime/newlineiter.H>
#include <x/mime/bodystartiter.H>
#include <x/mime/headeriter.H>
#include <map>
#include <iterator>
#include <iostream>

class headercollector : public std::iterator<std::output_iterator_tag,
					     void, void, void, void> {

public:
	std::multimap<std::string, std::string> *h;
	std::string name;

	bool seen_contents_start;
	bool in_header_name;
	bool in_newline;
	bool in_fold;

	std::multimap<std::string, std::string>::iterator value;
	headercollector(std::multimap<std::string, std::string> *hArg)
		: h(hArg), in_header_name(false), seen_contents_start(false)
	{
	}

	void operator=(int c)
	{
		switch (c) {
		case x::mime::header_name_start:
			name.clear();
			in_header_name=true;
			return;
		case x::mime::header_name_end:
			value=h->insert(std::make_pair(name, ""));
			in_header_name=false;
			return;
		case x::mime::header_contents_start:
			seen_contents_start=true;
			in_newline=false;
			in_fold=false;
			return;
		case x::mime::header_contents_end:
			seen_contents_start=false;
			return;
		case x::mime::header_fold_start:
			in_fold=true;
			return;
		case x::mime::header_fold_end:
			in_fold=false;
			value->second.push_back(' ');
			return;
		case x::mime::newline_start:
			in_newline=true;
			return;
		case x::mime::newline_end:
			in_newline=false;
			return;
		}

		if (!x::mime::nontoken(c))
			return;

		if (in_header_name)
		{
			name.push_back(c);
			return;
		}

		if (!seen_contents_start || in_fold || in_newline)
			return;

		value->second.push_back(c);
	}

	headercollector &operator*()
	{
		return *this;
	}

	headercollector &operator++()
	{
		return *this;
	}

	headercollector &operator++(int)
	{
		return *this;
	}
};

int main()
{
	std::multimap<std::string, std::string> h;

	typedef x::mime::header_iter<headercollector> header_iter_t;

	typedef x::mime::bodystart_iter<header_iter_t> bodystart_iter_t;

	typedef x::mime::newline_iter<bodystart_iter_t> newline_iter_t;

	auto iter=std::copy(std::istreambuf_iterator<char>(std::cin),
			    std::istreambuf_iterator<char>(),
			    newline_iter_t::create
			    (bodystart_iter_t::create
			     (header_iter_t::create(&h))));

	iter.get()->eof();

	for (const auto &c:h)
	{
		std::cout << "Header: " << c.first << ", value: "
			  << c.second << std::endl;
	}
	return 0;
}

This example constructs a simple output iterator that receives the output sequence from a x::mime::header_iter, collects all headers in a std::multimap, then shows them:


$ cat headeriter.txt
Mime-Version: 1.0
Subject: subject line
   folded header

test
$ ./headeriter <headeriter.txt
Header: Mime-Version, value: 1.0
Header: Subject, value: subject line folded header

x::mime::header_collector

x::mime::header_collector implements a basic output iterator that turns the output sequence from a x::mime::header_iter into calls to a lambda or a functor:

#include <x/mime/newlineiter.H>
#include <x/mime/bodystartiter.H>
#include <x/mime/headeriter.H>
#include <x/mime/headercollector.H>
#include <map>
#include <iterator>
#include <iostream>

int main()
{
	typedef x::mime::header_iter<x::mime::header_collector> header_iter_t;

	typedef x::mime::bodystart_iter<header_iter_t> bodystart_iter_t;

	typedef x::mime::newline_iter<bodystart_iter_t> newline_iter_t;

	auto iter=std::copy(std::istreambuf_iterator<char>(std::cin),
			    std::istreambuf_iterator<char>(),
			    newline_iter_t::create
			    (bodystart_iter_t::create
			     (header_iter_t::create
			      (x::mime::header_collector::create
			       ([] (const std::string &name,
				    const std::string &name_lc,
				    const std::string &value)
		{
			std::cout << "Header: " << name
			<< ", value: " << value
			<< std::endl;
		})))));

	iter.get()->eof();
	return 0;
}

This produces the same results as the previous example, with two small, but important, differences.

  • x::mime::header_collector::create() instantiates an output iterator over the sequence from x::mime::header_iter, and calls the lambda or the functor that's passed to create(). The functor/lambda gets invoked with three parameters: the header name, the header name converted to lowercase, and the contents of the header.

  • x::mime::header_collector does not store the headers from the MIME object it iterates over into a container of any kind. The functor/lambda gets invoked as soon as the entire header name and contents get iterated over.