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:
The name of each header gets preceded by an
x::mime::header_name_start
and followed by an
x::mime::header_name_end
.
The contents of each header gets preceded by an
x::mime::header_contents_start
and followed by
an
x::mime::header_contents_end
.
x::mime::header_name_start
and
x::mime::header_name_end
are always followed by
x::mime::header_contents_start
and
x::mime::header_contents_end
, but
x::mime::header_contents_start
does not
immediately follow a
x::mime::header_name_end
.
The portion of the output sequence delimited by
x::mime::header_contents_start
and
x::mime::header_contents_end
excludes the
colon and whitespace that separates the header name from its
contents.
x::mime::header_iter
does not
remove values from the output sequence it receives, it only adds
these additional values.
For multiline header contents, the sequence delimited by an
x::mime::header_contents_start
and an
x::mime::header_contents_end
has
additional
x::mime::header_fold_start
and an
x::mime::header_fold_end
values that
delimiter the start and the end of the newline and leading spaces
on the continued header line. For the purpose of parsing the
headers contents, the output sequence between and including
x::mime::header_fold_start
and
x::mime::header_fold_end
is logically
equivalent to a single space character (as already mentioned,
x::mime::header_iter
does not
remove values from the output sequence it receives, it only adds
dditional values).
After
x::mime::header_iter
iterates over a
x::mime::body_start
,
the
x::mime::header_iter
passes it, and the
rest of the output sequence, with no further parsing or action.
#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.