1 #ifndef _MIMETIC_PARSER_ITPARSER_H_
2 #define _MIMETIC_PARSER_ITPARSER_H_
7 #include <mimetic/tree.h>
8 #include <mimetic/utils.h>
9 #include <mimetic/mimeentity.h>
18 template<
typename Iterator,
19 typename ItCategory=
typename std::iterator_traits<Iterator>::iterator_category>
27 template<
typename Iterator>
32 : m_me(me), m_iMask(imNone), m_lastBoundary(NoBoundary)
34 m_entityStack.push(&m_me);
36 virtual ~IteratorParser()
42 void iMask(
size_t mask) { m_iMask = mask; }
46 size_t iMask()
const {
return m_iMask; }
50 void run(Iterator bit, Iterator eit)
57 typedef std::list<std::string> BoundaryList;
83 Iterator m_bit, m_eit;
85 BoundaryList m_boundaryList;
86 BoundaryType m_lastBoundary;
87 std::stack<MimeEntity*> m_entityStack;
90 void appendPreambleBlock(
const char* buf,
int sz)
92 MimeEntity* pMe = m_entityStack.top();
93 pMe->body().preamble().append(buf,sz);
96 void appendEpilogueBlock(
const char* buf,
int sz)
98 MimeEntity* pMe = m_entityStack.top();
99 pMe->body().epilogue().append(buf,sz);
102 void appendBodyBlock(
const char* buf,
int sz)
104 MimeEntity* pMe = m_entityStack.top();
105 pMe->body().append(buf, sz);
108 std::string getBoundary()
110 const MimeEntity* pMe = m_entityStack.top();
111 const ContentType& ct = pMe->header().contentType();
112 return std::string(
"--") + ct.param(
"boundary");
122 MimeEntity* pMe = m_entityStack.top();
123 MimeEntity* pChild =
new MimeEntity;
124 pMe->body().parts().push_back(pChild);
125 m_entityStack.push(pChild);
130 MimeEntity* pMe = m_entityStack.top();
131 const Header& h = pMe->header();
134 const ContentType& ct = h.contentType();
137 else if (ct.type() ==
"message" && ct.subtype() ==
"rfc822")
143 void addField(
const std::string& name,
const std::string& value)
145 MimeEntity* pMe = m_entityStack.top();
146 Header& h = pMe->header();
147 Header::iterator it = h.insert(h.end(), Field());
152 BoundaryType isBoundary(
const std::string& line)
154 if(line.length() == 0 || line[0] !=
'-')
155 return m_lastBoundary = NoBoundary;
158 int lineLen = line.length();
159 BoundaryList::const_iterator bit,eit;
160 bit = m_boundaryList.begin(), eit = m_boundaryList.end();
161 for(;bit != eit; ++bit, ++level)
163 const std::string& b = *bit;
164 int bLen = b.length();
165 if(line.compare(0, bLen, b) == 0)
169 return m_lastBoundary=HigherLevelBoundary;
171 if(lineLen > bLen && line.compare(bLen,2,
"--") == 0)
172 return m_lastBoundary = ClosingBoundary;
174 return m_lastBoundary = Boundary;
177 return m_lastBoundary = NoBoundary;
180 inline bool isnl(
char c)
const
182 return (c == CR || c == LF);
185 inline bool isnl(
char a,
char b)
const
187 if(a == CR || a == LF)
188 if(b == (a == CR ? LF : CR))
199 return m_bit != m_eit;
201 void append(
char*& buf,
size_t& bufsz,
char c,
size_t& pos)
203 enum { alloc_block = 128};
208 int oldBufsz = bufsz;
210 bufsz = bufsz + alloc_block;
211 buf =
new char[bufsz+1];
214 assert(oldBufsz > 0);
215 memset(buf, 0, bufsz);
216 memcpy(buf, tmp, oldBufsz);
240 size_t nBufSz, vBufSz, nPos, vPos;
244 pos = nBufSz = vBufSz = nPos = vPos = 0;
245 status = (m_iMask & imHeader ? sIgnoreHeader : sInit);
247 while(m_bit != m_eit)
264 status = sWaitingName;
269 if(++m_bit == m_eit)
goto out;
271 if(c == (prev == CR ? LF : CR))
280 if(++m_bit == m_eit)
goto out;
282 if(c == (prev == CR ? LF : CR))
290 status = sWaitingFoldedValue;
301 addField(name,value);
306 status = (isnl(c) ? sNewline : sName);
313 case sWaitingFoldedValue:
316 append(value, vBufSz,
' ', vPos);
320 if(c > 32 && c < 127 && c !=
':') {
321 if(nPos > 0 && isblank(name[nPos-1]))
325 onBlock(name, nPos, peBody);
328 append(name, nBufSz, c, nPos);
329 }
else if(c ==
':') {
333 status = sIgnoreLine;
339 while(nPos > 0 && isblank(name[nPos-1]))
342 status = sWaitingValue;
343 }
else if(isblank(c)) {
349 append(name, nBufSz, c, nPos);
353 onBlock(name, nPos, peBody);
363 append(value, vBufSz, c, vPos);
369 if(++m_bit == m_eit)
goto out;
371 if(c == (prev == CR ? LF : CR))
395 jump_to_next_boundary();
397 copy_until_boundary(peBody);
403 if(m_iMask & imChildParts)
404 jump_to_next_boundary();
415 std::string boundary = getBoundary();
416 m_boundaryList.push_front(boundary);
419 pe = (m_iMask & imPreamble ? peIgnore : pePreamble );
420 copy_until_boundary(pe);
421 while(m_bit != m_eit)
423 switch(m_lastBoundary)
428 if(m_iMask & imChildParts)
429 jump_to_next_boundary();
436 case ClosingBoundary:
437 m_boundaryList.erase(m_boundaryList.begin());
439 pe=(m_iMask & imEpilogue? peIgnore: peEpilogue);
440 copy_until_boundary(pe);
442 case HigherLevelBoundary:
443 m_boundaryList.erase(m_boundaryList.begin());
448 inline void onBlock(
const char* block,
int sz, ParsingElem pe)
455 appendPreambleBlock(block, sz);
458 appendEpilogueBlock(block, sz);
461 appendBodyBlock(block, sz);
465 void jump_to_next_boundary()
467 copy_until_boundary(peIgnore);
472 virtual void copy_until_boundary(ParsingElem pe)
474 size_t pos, lines, eomsz = 0;
479 enum { blksz = 4096 };
485 while(m_bit != m_eit)
488 if(blkpos >= blksz - 2 - nlsz)
496 onBlock(block, blkpos, pe);
501 size_t llen = blkpos - sl_off;
502 onBlock(block, sl_off, pe);
503 memmove(block, block + sl_off, llen);
511 char nlbuf[3] = { 0, 0, 0 };
519 if(next == (c == CR ? LF : CR))
530 if(block[sl_off] ==
'-' && sl_off < blkpos &&
531 block[sl_off+1] ==
'-')
533 std::string Line(block+sl_off, blkpos-sl_off);
548 }
else if (sl_off==1 && isnl(block[0])) {
551 onBlock(block, sl_off, pe);
557 if(eom && pos >= eomsz)
559 char *line = block + sl_off;
561 for(; i < eomsz; i++)
562 if(eom[i] != line[i])
566 onBlock(block, sl_off,
573 for(
int i = 0; nlbuf[i] != 0; i++)
574 block[blkpos++] = nlbuf[i];
586 onBlock(block, blkpos, pe);
594 template<
typename Iterator>
595 struct IteratorParser<Iterator, std::forward_iterator_tag>:
596 public IteratorParser<Iterator, std::input_iterator_tag>
603 typedef IteratorParser<Iterator, std::input_iterator_tag> base_type;
604 IteratorParser(MimeEntity& me)
613 template<
typename Iterator>
614 struct IteratorParser<Iterator, std::bidirectional_iterator_tag>:
615 public IteratorParser<Iterator, std::forward_iterator_tag>
617 typedef IteratorParser<Iterator, std::forward_iterator_tag> base_type;
618 IteratorParser(MimeEntity& me)
627 template<
typename Iterator>
628 struct IteratorParser<Iterator, std::random_access_iterator_tag>:
629 public IteratorParser<Iterator, std::bidirectional_iterator_tag>
631 typedef IteratorParser<Iterator, std::bidirectional_iterator_tag> base_type;
632 IteratorParser(MimeEntity& me)
637 using base_type::peIgnore;
638 using base_type::pePreamble;
639 using base_type::peBody;
640 using base_type::peEpilogue;
642 using base_type::NoBoundary;
643 using base_type::Boundary;
644 using base_type::ClosingBoundary;
645 using base_type::HigherLevelBoundary;
647 using base_type::m_boundaryList;
648 using base_type::m_lastBoundary;
649 using base_type::m_entityStack;
650 using base_type::m_me;
651 using base_type::m_iMask;
652 using base_type::m_bit;
653 using base_type::m_eit;
654 using base_type::isnl;
656 typedef TreeNode<char> BoundaryTree;
657 inline void onBlock(Iterator bit,
int size, ParsingElem pe)
661 Iterator eit = bit + size;
662 MimeEntity* pMe = m_entityStack.top();
666 pMe->body().preamble().append(bit, eit);
669 pMe->body().epilogue().append(bit, eit);
672 pMe->body().append(bit, eit);
676 void copy_until_boundary(ParsingElem pe)
679 if(m_boundaryList.empty())
681 onBlock(m_bit, m_eit-m_bit, pe);
688 typename base_type::BoundaryList::const_iterator
689 bBit = m_boundaryList.begin(), bEit = m_boundaryList.end();
690 m_lastBoundary = NoBoundary;
692 for( ;bBit != bEit; ++bBit, ++depth)
694 const std::string& boundary = *bBit;
696 if( (off=utils::find_bm(m_bit,m_eit,boundary)) != m_eit)
698 Iterator base = m_bit;
699 size_t block_sz = off - base;
701 (depth ? HigherLevelBoundary: Boundary);
702 off += boundary.length();
704 if(off<m_eit-1 && *off ==
'-' && *(off+1) ==
'-')
706 m_lastBoundary = ClosingBoundary;
709 if(m_bit < m_eit-1 && isnl(*m_bit))
713 if(isnl(next) && next != c)
720 Iterator p = base + block_sz;
721 char a = *--p, b = *--p;
727 onBlock(base, block_sz, pe);
730 onBlock(m_bit, m_eit-m_bit, pe);
735 BoundaryTree m_boundaryTree;
736 void buildBoundaryTree()
738 m_boundaryTree = BoundaryTree();
739 typename base_type::BoundaryList::const_iterator
740 bit = m_boundaryList.begin(), eit = m_boundaryList.end();
741 BoundaryTree::NodeList *pChilds;
742 BoundaryTree::NodeList::iterator it;
744 for( ; bit != eit; ++bit)
746 pChilds = &m_boundaryTree.childList();
747 it = pChilds->begin();
748 const char *w = bit->c_str();
751 it = find_if(pChilds->begin(), pChilds->end(),
752 FindNodePred<char>(*w));
753 if( it == pChilds->end() )
754 it = pChilds->insert(pChilds->end(),*w);
755 pChilds = &it->childList();
Represent a MIME entity.
Definition: mimeentity.h:37
Parse the input reading from an iterator.
Definition: itparser.h:20