Added ability to parse directly from an input stream (eg. file). This allows very big messages to be parsed without loading the whole message data into memory.

This commit is contained in:
Vincent Richard 2012-04-16 22:32:33 +02:00
parent cc49395dd2
commit 4f33877820
74 changed files with 1637 additions and 372 deletions

View File

@ -2,6 +2,12 @@
VERSION 0.9.2svn
================
2012-04-16 Vincent Richard <vincent@vincent-richard.net>
* MIME Parser can now operate directly on an input stream (eg. file).
This allows very big messages to be parsed without loading the whole
message data into memory.
2010-11-16 Vincent Richard <vincent@vincent-richard.net>
* Started version 0.9.2.

View File

@ -153,11 +153,14 @@ libvmime_sources = [
'utility/inputStreamSocketAdapter.cpp', 'utility/inputStreamSocketAdapter.hpp',
'utility/inputStreamStringAdapter.cpp', 'utility/inputStreamStringAdapter.hpp',
'utility/inputStreamStringProxyAdapter.cpp', 'utility/inputStreamStringProxyAdapter.hpp',
'utility/seekableInputStream.hpp',
'utility/seekableInputStreamRegionAdapter.cpp', 'utility/seekableInputStreamRegionAdapter.hpp',
'utility/outputStream.cpp', 'utility/outputStream.hpp',
'utility/outputStreamAdapter.cpp', 'utility/outputStreamAdapter.hpp',
'utility/outputStreamByteArrayAdapter.cpp', 'utility/outputStreamByteArrayAdapter.hpp',
'utility/outputStreamSocketAdapter.cpp', 'utility/outputStreamSocketAdapter.hpp',
'utility/outputStreamStringAdapter.cpp', 'utility/outputStreamStringAdapter.hpp',
'utility/parserInputStreamAdapter.cpp', 'utility/parserInputStreamAdapter.hpp',
'utility/stringProxy.cpp', 'utility/stringProxy.hpp',
'utility/stringUtils.cpp', 'utility/stringUtils.hpp',
'utility/url.cpp', 'utility/url.hpp',

View File

@ -50,7 +50,7 @@ addressList::~addressList()
}
void addressList::parse(const string& buffer, const string::size_type position,
void addressList::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
removeAllAddresses();
@ -72,7 +72,7 @@ void addressList::parse(const string& buffer, const string::size_type position,
}
void addressList::generate(utility::outputStream& os, const string::size_type maxLineLength,
void addressList::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;
@ -248,9 +248,9 @@ const std::vector <ref <address> > addressList::getAddressList()
}
const std::vector <ref <const component> > addressList::getChildComponents() const
const std::vector <ref <component> > addressList::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
copy_vector(m_list, list);

View File

@ -31,10 +31,13 @@
#include "vmime/utility/random.hpp"
#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
#include "vmime/parserHelpers.hpp"
#include "vmime/emptyContentHandler.hpp"
#include "vmime/stringContentHandler.hpp"
#include "vmime/streamContentHandler.hpp"
namespace vmime
@ -52,11 +55,28 @@ body::~body()
}
void body::parse(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
void body::parseImpl
(ref <utility::parserInputStreamAdapter> parser,
const utility::stream::size_type position,
const utility::stream::size_type end,
utility::stream::size_type* newPosition)
{
removeAllParts();
m_prologText.clear();
m_epilogText.clear();
if (end == position)
{
setParsedBounds(position, end);
if (newPosition)
*newPosition = end;
return;
}
// Check whether the body is a MIME-multipart
bool isMultipart = false;
string boundary;
@ -80,37 +100,61 @@ void body::parse(const string& buffer, const string::size_type position,
{
// No "boundary" parameter specified: we can try to
// guess it by scanning the body contents...
string::size_type pos = buffer.find("\n--", position);
utility::stream::size_type pos = position;
if ((pos != string::npos) && (pos < end))
parser->seek(pos);
if (pos + 2 < end && parser->matchBytes("--", 2))
{
pos += 3;
pos += 2;
}
else
{
pos = parser->findNext("\n--", position);
const string::size_type start = pos;
if ((pos != utility::stream::npos) && (pos + 3 < end))
pos += 3; // skip \n--
}
char_t c = buffer[pos];
string::size_type length = 0;
if ((pos != utility::stream::npos) && (pos < end))
{
parser->seek(pos);
// Read some bytes after boundary separator
utility::stream::value_type buffer[256];
const utility::stream::size_type bufferLen =
parser->read(buffer, std::min(end - pos, sizeof(buffer) / sizeof(buffer[0])));
buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0';
// Extract boundary from buffer (stop at first CR or LF).
// We have to stop after a reasonnably long boundary length (100)
// not to take the whole body contents for a boundary...
while (pos < end && length < 100 && !(c == '\r' || c == '\n'))
string::value_type boundaryBytes[100];
string::size_type boundaryLen = 0;
for (string::value_type c = buffer[0] ;
boundaryLen < bufferLen && boundaryLen < 100 && !(c == '\r' || c == '\n') ;
c = buffer[++boundaryLen])
{
++length;
c = buffer[pos++];
boundaryBytes[boundaryLen] = buffer[boundaryLen];
}
if (pos < end && length < 100)
if (boundaryLen >= 1 && boundaryLen < 100)
{
// RFC #1521, Page 31:
// "...the boundary parameter, which consists of 1 to 70
// characters from a set of characters known to be very
// robust through email gateways, and NOT ending with
// white space..."
while (pos != start && parserHelpers::isSpace(buffer[pos - 1]))
--pos;
while (boundaryLen != 0 &&
parserHelpers::isSpace(boundaryBytes[boundaryLen - 1]))
{
boundaryLen--;
}
boundary = string(buffer.begin() + start,
buffer.begin() + pos);
if (boundaryLen >= 1)
boundary = string(boundaryBytes, boundaryBytes + boundaryLen);
}
}
}
@ -126,51 +170,79 @@ void body::parse(const string& buffer, const string::size_type position,
{
const string boundarySep("--" + boundary);
string::size_type partStart = position;
string::size_type pos = position;
utility::stream::size_type partStart = position;
utility::stream::size_type pos = position;
bool lastPart = false;
while (pos != string::npos && pos < end)
while (pos != utility::stream::npos && pos < end)
{
pos = buffer.find(boundarySep, pos);
pos = parser->findNext(boundarySep, pos);
if (pos == string::npos ||
((pos == 0 || buffer[pos - 1] == '\n') &&
(buffer[pos + boundarySep.length()] == '\r' ||
buffer[pos + boundarySep.length()] == '\n' ||
buffer[pos + boundarySep.length()] == '-'
)
)
)
if (pos == utility::stream::npos)
break; // not found
if (pos != 0)
{
break;
parser->seek(pos - 1);
if (parser->peekByte() != '\n')
{
// Boundary is not at a beginning of a line
pos++;
continue;
}
parser->skip(1 + boundarySep.length());
}
else
{
parser->seek(pos + boundarySep.length());
}
// boundary not a beginning of line, or just a prefix of another, continue the search.
const utility::stream::value_type next = parser->peekByte();
if (next == '\r' || next == '\n' || next == '-')
break;
// Boundary is a prefix of another, continue the search
pos++;
}
if (pos != string::npos && pos < end)
if (pos != utility::stream::npos && pos < end)
{
vmime::text text;
text.parse(buffer, position, pos);
text.parse(parser, position, pos);
m_prologText = text.getWholeBuffer();
}
for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index)
for (int index = 0 ; !lastPart && (pos != utility::stream::npos) && (pos < end) ; ++index)
{
string::size_type partEnd = pos;
utility::stream::size_type partEnd = pos;
// Get rid of the [CR]LF just before the boundary string
if (pos >= (position + 1) && buffer[pos - 1] == '\n') --partEnd;
if (pos >= (position + 2) && buffer[pos - 2] == '\r') --partEnd;
if (pos >= (position + 1))
{
parser->seek(pos - 1);
if (parser->peekByte() == '\n')
--partEnd;
}
if (pos >= (position + 2))
{
parser->seek(pos - 2);
if (parser->peekByte() == '\r')
--partEnd;
}
// Check whether it is the last part (boundary terminated by "--")
pos += boundarySep.length();
parser->seek(pos);
if (pos + 1 < end && buffer[pos] == '-' && buffer[pos + 1] == '-')
if (pos + 1 < end && parser->matchBytes("--", 2))
{
lastPart = true;
pos += 2;
@ -180,15 +252,15 @@ void body::parse(const string& buffer, const string::size_type position,
// "...(If a boundary appears to end with white space, the
// white space must be presumed to have been added by a
// gateway, and must be deleted.)..."
while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t'))
++pos;
parser->seek(pos);
pos += parser->skipIf(parserHelpers::isSpaceOrTab, end);
// End of boundary line
if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] =='\n')
if (pos + 1 < end && parser->matchBytes("\r\n", 2))
{
pos += 2;
}
else if (pos < end && buffer[pos] == '\n')
else if (pos < end && parser->peekByte() == '\n')
{
++pos;
}
@ -202,7 +274,7 @@ void body::parse(const string& buffer, const string::size_type position,
if (partEnd < partStart)
std::swap(partStart, partEnd);
part->parse(buffer, partStart, partEnd, NULL);
part->parse(parser, partStart, partEnd, NULL);
part->m_parent = m_part;
m_parts.push_back(part);
@ -210,23 +282,37 @@ void body::parse(const string& buffer, const string::size_type position,
partStart = pos;
while (pos != string::npos && pos < end)
while (pos != utility::stream::npos && pos < end)
{
pos = buffer.find(boundarySep, pos);
pos = parser->findNext(boundarySep, pos);
if (pos == string::npos ||
((pos == 0 || buffer[pos - 1] == '\n') &&
(buffer[pos + boundarySep.length()] == '\r' ||
buffer[pos + boundarySep.length()] == '\n' ||
buffer[pos + boundarySep.length()] == '-'
)
)
)
if (pos == utility::stream::npos)
break; // not found
if (pos != 0)
{
break;
parser->seek(pos - 1);
if (parser->peekByte() != '\n')
{
// Boundary is not at a beginning of a line
pos++;
continue;
}
parser->skip(1 + boundarySep.length());
}
else
{
parser->seek(pos + boundarySep.length());
}
// boundary not a beginning of line, or just a prefix of another, continue the search.
const utility::stream::value_type next = parser->peekByte();
if (next == '\r' || next == '\n' || next == '-')
break;
// Boundary is a prefix of another, continue the search
pos++;
}
}
@ -234,13 +320,13 @@ void body::parse(const string& buffer, const string::size_type position,
m_contents = vmime::create <emptyContentHandler>();
// Last part was not found: recover from missing boundary
if (!lastPart && pos == string::npos)
if (!lastPart && pos == utility::stream::npos)
{
ref <bodyPart> part = vmime::create <bodyPart>();
try
{
part->parse(buffer, partStart, end);
part->parse(parser, partStart, end);
}
catch (std::exception&)
{
@ -255,7 +341,7 @@ void body::parse(const string& buffer, const string::size_type position,
else if (partStart < end)
{
vmime::text text;
text.parse(buffer, partStart, end);
text.parse(parser, partStart, end);
m_epilogText = text.getWholeBuffer();
}
@ -282,7 +368,13 @@ void body::parse(const string& buffer, const string::size_type position,
}
// Extract the (encoded) contents
m_contents = vmime::create <stringContentHandler>(buffer, position, end, enc);
const utility::stream::size_type length = end - position;
ref <utility::inputStream> contentStream =
vmime::create <utility::seekableInputStreamRegionAdapter>
(parser->getUnderlyingStream(), position, length);
m_contents = vmime::create <streamContentHandler>(contentStream, length, enc);
}
setParsedBounds(position, end);
@ -292,7 +384,7 @@ void body::parse(const string& buffer, const string::size_type position,
}
void body::generate(utility::outputStream& os, const string::size_type maxLineLength,
void body::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type /* curLinePos */, string::size_type* newLinePos) const
{
// MIME-Multipart
@ -862,9 +954,9 @@ const std::vector <ref <bodyPart> > body::getPartList()
}
const std::vector <ref <const component> > body::getChildComponents() const
const std::vector <ref <component> > body::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
copy_vector(m_parts, list);

View File

@ -46,15 +46,18 @@ bodyPart::bodyPart(weak_ref <vmime::bodyPart> parentPart)
}
void bodyPart::parse(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
void bodyPart::parseImpl
(ref <utility::parserInputStreamAdapter> parser,
const utility::stream::size_type position,
const utility::stream::size_type end,
utility::stream::size_type* newPosition)
{
// Parse the headers
string::size_type pos = position;
m_header->parse(buffer, pos, end, &pos);
m_header->parse(parser, pos, end, &pos);
// Parse the body contents
m_body->parse(buffer, pos, end, NULL);
m_body->parse(parser, pos, end, NULL);
setParsedBounds(position, end);
@ -63,7 +66,7 @@ void bodyPart::parse(const string& buffer, const string::size_type position,
}
void bodyPart::generate(utility::outputStream& os, const string::size_type maxLineLength,
void bodyPart::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type /* curLinePos */, string::size_type* newLinePos) const
{
m_header->generate(os, maxLineLength);
@ -142,9 +145,9 @@ ref <const bodyPart> bodyPart::getParentPart() const
}
const std::vector <ref <const component> > bodyPart::getChildComponents() const
const std::vector <ref <component> > bodyPart::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
list.push_back(m_header);
list.push_back(m_body);

View File

@ -57,7 +57,7 @@ charset::charset(const char* name)
}
void charset::parse(const string& buffer, const string::size_type position,
void charset::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
m_name = utility::stringUtils::trim
@ -74,7 +74,7 @@ void charset::parse(const string& buffer, const string::size_type position,
}
void charset::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
void charset::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
os << m_name;
@ -142,9 +142,9 @@ void charset::copyFrom(const component& other)
}
const std::vector <ref <const component> > charset::getChildComponents() const
const std::vector <ref <component> > charset::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -23,6 +23,9 @@
#include "vmime/component.hpp"
#include "vmime/base.hpp"
#include "vmime/utility/streamUtils.hpp"
#include "vmime/utility/inputStreamStringAdapter.hpp"
#include "vmime/utility/outputStreamAdapter.hpp"
#include <sstream>
@ -43,9 +46,102 @@ component::~component()
}
void component::parse
(ref <utility::inputStream> inputStream, const utility::stream::size_type length)
{
parse(inputStream, 0, length, NULL);
}
void component::parse
(ref <utility::inputStream> inputStream, const utility::stream::size_type position,
const utility::stream::size_type end, utility::stream::size_type* newPosition)
{
m_parsedOffset = m_parsedLength = 0;
ref <utility::seekableInputStream> seekableStream =
inputStream.dynamicCast <utility::seekableInputStream>();
if (seekableStream == NULL || end == 0)
{
// Read the whole stream into a buffer
std::ostringstream oss;
utility::outputStreamAdapter ossAdapter(oss);
utility::bufferedStreamCopyRange(*inputStream, ossAdapter, position, end - position);
const string buffer = oss.str();
parseImpl(buffer, 0, buffer.length(), NULL);
}
else
{
ref <utility::parserInputStreamAdapter> parser =
vmime::create <utility::parserInputStreamAdapter>(seekableStream);
parseImpl(parser, position, end, newPosition);
}
}
void component::parse(const string& buffer)
{
parse(buffer, 0, buffer.length(), NULL);
m_parsedOffset = m_parsedLength = 0;
parseImpl(buffer, 0, buffer.length(), NULL);
}
void component::parse
(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
m_parsedOffset = m_parsedLength = 0;
parseImpl(buffer, position, end, newPosition);
}
void component::offsetParsedBounds(const utility::stream::size_type offset)
{
// Offset parsed bounds of this component
if (m_parsedLength != 0)
m_parsedOffset += offset;
// Offset parsed bounds of our children
std::vector <ref <component> > children = getChildComponents();
for (unsigned int i = 0, n = children.size() ; i < n ; ++i)
children[i]->offsetParsedBounds(offset);
}
void component::parseImpl
(ref <utility::parserInputStreamAdapter> parser, const utility::stream::size_type position,
const utility::stream::size_type end, utility::stream::size_type* newPosition)
{
const std::string buffer = parser->extract(position, end);
parseImpl(buffer, 0, buffer.length(), newPosition);
// Recursivey offset parsed bounds on children
if (position != 0)
offsetParsedBounds(position);
if (newPosition != NULL)
*newPosition += position;
}
void component::parseImpl
(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
ref <utility::seekableInputStream> stream =
vmime::create <utility::inputStreamStringAdapter>(buffer);
ref <utility::parserInputStreamAdapter> parser =
vmime::create <utility::parserInputStreamAdapter>(stream);
parseImpl(parser, position, end, newPosition);
}
@ -61,6 +157,26 @@ const string component::generate(const string::size_type maxLineLength,
}
void component::generate
(utility::outputStream& os,
const string::size_type maxLineLength,
const string::size_type curLinePos,
string::size_type* newLinePos) const
{
generateImpl(os, maxLineLength, curLinePos, newLinePos);
}
void component::generate
(ref <utility::outputStream> os,
const string::size_type maxLineLength,
const string::size_type curLinePos,
string::size_type* newLinePos) const
{
generateImpl(*os, maxLineLength, curLinePos, newLinePos);
}
string::size_type component::getParsedOffset() const
{
return (m_parsedOffset);
@ -80,22 +196,5 @@ void component::setParsedBounds(const string::size_type start, const string::siz
}
const std::vector <ref <component> > component::getChildComponents()
{
const std::vector <ref <const component> > constList =
const_cast <const component*>(this)->getChildComponents();
} // vmime
std::vector <ref <component> > list;
const std::vector <ref <const component> >::size_type count = constList.size();
list.resize(count);
for (std::vector <ref <const component> >::size_type i = 0 ; i < count ; ++i)
list[i] = constList[i].constCast <component>();
return (list);
}
}

View File

@ -47,7 +47,7 @@ contentDisposition::contentDisposition(const contentDisposition& type)
}
void contentDisposition::parse(const string& buffer, const string::size_type position,
void contentDisposition::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
m_name = utility::stringUtils::trim(utility::stringUtils::toLower
@ -60,7 +60,7 @@ void contentDisposition::parse(const string& buffer, const string::size_type pos
}
void contentDisposition::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
void contentDisposition::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
os << m_name;
@ -122,9 +122,9 @@ void contentDisposition::setName(const string& name)
}
const std::vector <ref <const component> > contentDisposition::getChildComponents() const
const std::vector <ref <component> > contentDisposition::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -67,7 +67,7 @@ zone = "UT" / "GMT" ; Universal Time
*/
void datetime::parse(const string& buffer, const string::size_type position,
void datetime::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -588,7 +588,7 @@ void datetime::parse(const string& buffer, const string::size_type position,
}
void datetime::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
void datetime::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
static const string::value_type* dayNames[] =
@ -784,9 +784,9 @@ ref <component> datetime::clone() const
}
const std::vector <ref <const component> > datetime::getChildComponents() const
const std::vector <ref <component> > datetime::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -79,9 +79,9 @@ disposition& disposition::operator=(const disposition& other)
}
const std::vector <ref <const component> > disposition::getChildComponents() const
const std::vector <ref <component> > disposition::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}
@ -171,7 +171,7 @@ const std::vector <string> disposition::getModifierList() const
}
void disposition::parse(const string& buffer, const string::size_type position,
void disposition::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
// disposition-mode ";" disposition-type
@ -276,7 +276,7 @@ void disposition::parse(const string& buffer, const string::size_type position,
}
void disposition::generate(utility::outputStream& os, const string::size_type maxLineLength,
void disposition::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;

View File

@ -61,7 +61,7 @@ encoding::encoding(const encoding& enc)
}
void encoding::parse(const string& buffer, const string::size_type position,
void encoding::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
m_usage = USAGE_UNKNOWN;
@ -80,7 +80,7 @@ void encoding::parse(const string& buffer, const string::size_type position,
}
void encoding::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
void encoding::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
os << m_name;
@ -268,9 +268,9 @@ void encoding::setUsage(const EncodingUsage usage)
}
const std::vector <ref <const component> > encoding::getChildComponents() const
const std::vector <ref <component> > encoding::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -61,7 +61,7 @@ field-body-contents =
specials tokens, or else consisting of texts>
*/
void header::parse(const string& buffer, const string::size_type position,
void header::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
string::size_type pos = position;
@ -83,7 +83,7 @@ void header::parse(const string& buffer, const string::size_type position,
}
void header::generate(utility::outputStream& os, const string::size_type maxLineLength,
void header::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type /* curLinePos */, string::size_type* newLinePos) const
{
// Generate the fields
@ -337,9 +337,9 @@ const std::vector <ref <headerField> > header::getFieldList()
}
const std::vector <ref <const component> > header::getChildComponents() const
const std::vector <ref <component> > header::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
copy_vector(m_fields, list);

View File

@ -262,14 +262,14 @@ ref <headerField> headerField::parseNext(const string& buffer, const string::siz
}
void headerField::parse(const string& buffer, const string::size_type position, const string::size_type end,
void headerField::parseImpl(const string& buffer, const string::size_type position, const string::size_type end,
string::size_type* newPosition)
{
m_value->parse(buffer, position, end, newPosition);
}
void headerField::generate(utility::outputStream& os, const string::size_type maxLineLength,
void headerField::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
os << m_name + ": ";
@ -296,9 +296,9 @@ bool headerField::isCustom() const
}
const std::vector <ref <const component> > headerField::getChildComponents() const
const std::vector <ref <component> > headerField::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
if (m_value)
list.push_back(m_value);

View File

@ -65,7 +65,7 @@ angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
*/
void mailbox::parse(const string& buffer, const string::size_type position,
void mailbox::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -343,7 +343,7 @@ void mailbox::parse(const string& buffer, const string::size_type position,
}
void mailbox::generate(utility::outputStream& os, const string::size_type maxLineLength,
void mailbox::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
if (m_name.isEmpty())
@ -514,9 +514,9 @@ void mailbox::setEmail(const string& email)
}
const std::vector <ref <const component> > mailbox::getChildComponents() const
const std::vector <ref <component> > mailbox::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -54,7 +54,7 @@ mailboxGroup::~mailboxGroup()
}
void mailboxGroup::parse(const string& buffer, const string::size_type position,
void mailboxGroup::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -111,7 +111,7 @@ void mailboxGroup::parse(const string& buffer, const string::size_type position,
}
void mailboxGroup::generate(utility::outputStream& os, const string::size_type maxLineLength,
void mailboxGroup::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
// We have to encode the name:
@ -348,9 +348,9 @@ const std::vector <ref <mailbox> > mailboxGroup::getMailboxList()
}
const std::vector <ref <const component> > mailboxGroup::getChildComponents() const
const std::vector <ref <component> > mailboxGroup::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
copy_vector(m_list, list);

View File

@ -190,20 +190,20 @@ mailboxList& mailboxList::operator=(const mailboxList& other)
}
const std::vector <ref <const component> > mailboxList::getChildComponents() const
const std::vector <ref <component> > mailboxList::getChildComponents()
{
return (m_list.getChildComponents());
}
void mailboxList::parse(const string& buffer, const string::size_type position,
void mailboxList::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
m_list.parse(buffer, position, end, newPosition);
}
void mailboxList::generate(utility::outputStream& os, const string::size_type maxLineLength,
void mailboxList::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
m_list.generate(os, maxLineLength, curLinePos, newLinePos);

View File

@ -48,7 +48,7 @@ mediaType::mediaType(const string& type, const string& subType)
}
void mediaType::parse(const string& buffer, const string::size_type position,
void mediaType::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -82,7 +82,7 @@ void mediaType::parse(const string& buffer, const string::size_type position,
}
void mediaType::generate(utility::outputStream& os, const string::size_type maxLineLength,
void mediaType::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
const string value = m_type + "/" + m_subType;
@ -176,9 +176,9 @@ void mediaType::setFromString(const string& type)
}
const std::vector <ref <const component> > mediaType::getChildComponents() const
const std::vector <ref <component> > mediaType::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -61,9 +61,14 @@ const string message::generate(const string::size_type maxLineLength,
}
void message::parse(const string& buffer)
void message::generate
(ref <utility::outputStream> os,
const string::size_type maxLineLength,
const string::size_type curLinePos,
string::size_type* newLinePos) const
{
bodyPart::parse(buffer);
bodyPart::generate(os, maxLineLength, curLinePos, newLinePos);
}

View File

@ -61,7 +61,7 @@ messageId::messageId(const string& left, const string& right)
msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
*/
void messageId::parse(const string& buffer, const string::size_type position,
void messageId::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -185,7 +185,7 @@ const string messageId::getId() const
}
void messageId::generate(utility::outputStream& os, const string::size_type maxLineLength,
void messageId::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;
@ -288,9 +288,9 @@ void messageId::setRight(const string& right)
}
const std::vector <ref <const component> > messageId::getChildComponents() const
const std::vector <ref <component> > messageId::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -74,9 +74,9 @@ messageIdSequence& messageIdSequence::operator=(const messageIdSequence& other)
}
const std::vector <ref <const component> > messageIdSequence::getChildComponents() const
const std::vector <ref <component> > messageIdSequence::getChildComponents()
{
std::vector <ref <const component> > res;
std::vector <ref <component> > res;
copy_vector(m_list, res);
@ -84,7 +84,7 @@ const std::vector <ref <const component> > messageIdSequence::getChildComponents
}
void messageIdSequence::parse(const string& buffer, const string::size_type position,
void messageIdSequence::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
removeAllMessageIds();
@ -106,7 +106,7 @@ void messageIdSequence::parse(const string& buffer, const string::size_type posi
}
void messageIdSequence::generate(utility::outputStream& os, const string::size_type maxLineLength,
void messageIdSequence::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;

View File

@ -36,19 +36,19 @@ namespace vmime
parameter::parameter(const string& name)
: m_name(name)
: m_name(name), m_value(vmime::create <word>())
{
}
parameter::parameter(const string& name, const word& value)
: m_name(name), m_value(value)
: m_name(name), m_value(vmime::create <word>(value))
{
}
parameter::parameter(const string& name, const string& value)
: m_name(name), m_value(value)
: m_name(name), m_value(vmime::create <word>(value))
{
}
@ -73,7 +73,7 @@ void parameter::copyFrom(const component& other)
const parameter& param = dynamic_cast <const parameter&>(other);
m_name = param.m_name;
m_value.copyFrom(param.m_value);
m_value->copyFrom(*param.m_value);
}
@ -92,7 +92,7 @@ const string& parameter::getName() const
const word& parameter::getValue() const
{
return m_value;
return *m_value;
}
@ -109,15 +109,15 @@ void parameter::setValue(const component& value)
void parameter::setValue(const word& value)
{
m_value = value;
*m_value = value;
}
void parameter::parse(const string& buffer, const string::size_type position,
void parameter::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
m_value.setBuffer(string(buffer.begin() + position, buffer.begin() + end));
m_value.setCharset(charset(charsets::US_ASCII));
m_value->setBuffer(string(buffer.begin() + position, buffer.begin() + end));
m_value->setCharset(charset(charsets::US_ASCII));
if (newPosition)
*newPosition = end;
@ -248,16 +248,16 @@ void parameter::parse(const std::vector <valueChunk>& chunks)
}
}
m_value.setBuffer(value.str());
m_value.setCharset(ch);
m_value->setBuffer(value.str());
m_value->setCharset(ch);
}
void parameter::generate(utility::outputStream& os, const string::size_type maxLineLength,
void parameter::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
const string& name = m_name;
const string& value = m_value.getBuffer();
const string& value = m_value->getBuffer();
// For compatibility with implementations that do not understand RFC-2231,
// also generate a normal "7bit/us-ascii" parameter
@ -344,7 +344,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
// 7-bit (ASCII) bytes in the input will be used to determine if
// we need to encode the whole buffer.
encoding recommendedEnc;
const bool alwaysEncode = m_value.getCharset().getRecommendedEncoding(recommendedEnc);
const bool alwaysEncode = m_value->getCharset().getRecommendedEncoding(recommendedEnc);
bool extended = alwaysEncode;
if (needQuotedPrintable)
@ -352,7 +352,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
// Send the name in quoted-printable, so outlook express et.al.
// will understand the real filename
size_t oldLen = sevenBitBuffer.length();
m_value.generate(sevenBitStream);
m_value->generate(sevenBitStream);
pos += sevenBitBuffer.length() - oldLen;
extended = true; // also send with RFC-2231 encoding
}
@ -429,7 +429,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
// + at least 5 characters for the value
const string::size_type firstSectionLength =
name.length() + 4 /* *0*= */ + 2 /* '' */
+ m_value.getCharset().getName().length();
+ m_value->getCharset().getName().length();
if (pos + firstSectionLength + 5 >= maxLineLength)
{
@ -539,7 +539,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
if (sectionNumber == 0)
{
os << m_value.getCharset().getName();
os << m_value->getCharset().getName();
os << '\'' << /* No language */ '\'';
}
@ -570,11 +570,11 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
}
const std::vector <ref <const component> > parameter::getChildComponents() const
const std::vector <ref <component> > parameter::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
list.push_back(ref <const component>::fromPtr(&m_value));
list.push_back(m_value);
return list;
}

View File

@ -78,7 +78,7 @@ struct paramInfo
#endif // VMIME_BUILDING_DOC
void parameterizedHeaderField::parse(const string& buffer, const string::size_type position,
void parameterizedHeaderField::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -328,13 +328,13 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty
}
void parameterizedHeaderField::generate(utility::outputStream& os, const string::size_type maxLineLength,
void parameterizedHeaderField::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;
// Parent header field
headerField::generate(os, maxLineLength, pos, &pos);
headerField::generateImpl(os, maxLineLength, pos, &pos);
// Parameters
for (std::vector <ref <parameter> >::const_iterator
@ -552,11 +552,11 @@ const std::vector <ref <parameter> > parameterizedHeaderField::getParameterList(
}
const std::vector <ref <const component> > parameterizedHeaderField::getChildComponents() const
const std::vector <ref <component> > parameterizedHeaderField::getChildComponents()
{
std::vector <ref <const component> > list = headerField::getChildComponents();
std::vector <ref <component> > list = headerField::getChildComponents();
for (std::vector <ref <parameter> >::const_iterator it = m_params.begin() ;
for (std::vector <ref <parameter> >::iterator it = m_params.begin() ;
it != m_params.end() ; ++it)
{
list.push_back(*it);

View File

@ -106,14 +106,14 @@ path& path::operator=(const path& other)
}
const std::vector <ref <const component> > path::getChildComponents() const
const std::vector <ref <component> > path::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}
void path::parse(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
void path::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
string::size_type pos = position;
@ -165,8 +165,8 @@ void path::parse(const string& buffer, const string::size_type position,
}
void path::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
const string::size_type curLinePos, string::size_type* newLinePos) const
void path::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
if (m_localPart.empty() && m_domain.empty())
{

View File

@ -224,6 +224,26 @@ vmime::utility::stream::size_type posixFileReaderInputStream::skip(const size_ty
}
vmime::utility::stream::size_type posixFileReaderInputStream::getPosition() const
{
const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR);
if (curPos == off_t(-1))
posixFileSystemFactory::reportError(m_path, errno);
return static_cast <size_type>(curPos);
}
void posixFileReaderInputStream::seek(const size_type pos)
{
const off_t newPos = ::lseek(m_fd, pos, SEEK_SET);
if (newPos == off_t(-1))
posixFileSystemFactory::reportError(m_path, errno);
}
//
// posixFileWriter

View File

@ -479,6 +479,24 @@ vmime::utility::stream::size_type windowsFileReaderInputStream::skip(const size_
return (dwNewPos - dwCurPos);
}
vmime::utility::stream::size_type windowsFileReaderInputStream::getPosition() const
{
DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
if (dwCurPos == INVALID_SET_FILE_POINTER)
windowsFileSystemFactory::reportError(m_path, GetLastError());
return static_cast <size_type>(dwCurPos);
}
void windowsFileReaderInputStream::seek(const size_type pos)
{
DWORD dwNewPos = SetFilePointer(m_hFile, (LONG)pos, NULL, FILE_BEGIN);
if (dwNewPos == INVALID_SET_FILE_POINTER)
windowsFileSystemFactory::reportError(m_path, GetLastError());
}
windowsFileWriter::windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath)
: m_path(path), m_nativePath(nativePath)
{

View File

@ -57,7 +57,7 @@ relay::relay(const relay& r)
["for" addr-spec] ; initial form
*/
void relay::parse(const string& buffer, const string::size_type position,
void relay::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
const string::value_type* const pend = buffer.data() + end;
@ -198,7 +198,7 @@ void relay::parse(const string& buffer, const string::size_type position,
}
void relay::generate(utility::outputStream& os, const string::size_type maxLineLength,
void relay::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
std::ostringstream oss;
@ -338,10 +338,10 @@ std::vector <string>& relay::getWithList()
}
const std::vector <ref <const component> > relay::getChildComponents() const
const std::vector <ref <component> > relay::getChildComponents()
{
// TODO: should fields inherit from 'component'? (using typeAdapter)
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -25,6 +25,7 @@
#include "vmime/utility/outputStreamAdapter.hpp"
#include "vmime/utility/inputStreamStringAdapter.hpp"
#include "vmime/utility/seekableInputStream.hpp"
#include "vmime/utility/streamUtils.hpp"
@ -207,6 +208,9 @@ const vmime::encoding& streamContentHandler::getEncoding() const
bool streamContentHandler::isBuffered() const
{
if (m_stream.dynamicCast <utility::seekableInputStream>() != NULL)
return true;
// FIXME: some streams can be resetted
return false;
}

View File

@ -67,7 +67,7 @@ text::~text()
}
void text::parse(const string& buffer, const string::size_type position,
void text::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
removeAllWords();
@ -85,7 +85,7 @@ void text::parse(const string& buffer, const string::size_type position,
}
void text::generate(utility::outputStream& os, const string::size_type maxLineLength,
void text::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
encodeAndFold(os, maxLineLength, curLinePos, newLinePos, 0);
@ -389,9 +389,9 @@ text* text::decodeAndUnfold(const string& in, text* generateInExisting)
}
const std::vector <ref <const component> > text::getChildComponents() const
const std::vector <ref <component> > text::getChildComponents()
{
std::vector <ref <const component> > list;
std::vector <ref <component> > list;
copy_vector(m_words, list);

View File

@ -65,6 +65,18 @@ stream::size_type inputStreamAdapter::skip(const size_type count)
}
stream::size_type inputStreamAdapter::getPosition() const
{
return m_stream.tellg();
}
void inputStreamAdapter::seek(const size_type pos)
{
m_stream.seekg(pos, std::ios_base::beg);
}
} // utility
} // vmime

View File

@ -85,6 +85,19 @@ stream::size_type inputStreamByteBufferAdapter::skip(const size_type count)
}
stream::size_type inputStreamByteBufferAdapter::getPosition() const
{
return m_pos;
}
void inputStreamByteBufferAdapter::seek(const size_type pos)
{
if (pos <= m_length)
m_pos = pos;
}
} // utility
} // vmime

View File

@ -89,6 +89,19 @@ stream::size_type inputStreamStringAdapter::skip(const size_type count)
}
stream::size_type inputStreamStringAdapter::getPosition() const
{
return m_pos - m_begin;
}
void inputStreamStringAdapter::seek(const size_type pos)
{
if (m_begin + pos <= m_end)
m_pos = m_begin + pos;
}
} // utility
} // vmime

View File

@ -84,6 +84,19 @@ stream::size_type inputStreamStringProxyAdapter::skip(const size_type count)
}
stream::size_type inputStreamStringProxyAdapter::getPosition() const
{
return m_pos;
}
void inputStreamStringProxyAdapter::seek(const size_type pos)
{
if (pos <= m_buffer.length())
m_pos = pos;
}
} // utility
} // vmime

View File

@ -0,0 +1,162 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#include "vmime/utility/parserInputStreamAdapter.hpp"
namespace vmime {
namespace utility {
parserInputStreamAdapter::parserInputStreamAdapter(ref <seekableInputStream> stream)
: m_stream(stream)
{
}
bool parserInputStreamAdapter::eof() const
{
return m_stream->eof();
}
void parserInputStreamAdapter::reset()
{
m_stream->reset();
}
stream::size_type parserInputStreamAdapter::read
(value_type* const data, const size_type count)
{
return m_stream->read(data, count);
}
ref <seekableInputStream> parserInputStreamAdapter::getUnderlyingStream()
{
return m_stream;
}
const string parserInputStreamAdapter::extract(const size_type begin, const size_type end) const
{
const size_type initialPos = m_stream->getPosition();
try
{
value_type *buffer = new value_type[end - begin + 1];
m_stream->seek(begin);
const size_type readBytes = m_stream->read(buffer, end - begin);
buffer[readBytes] = '\0';
m_stream->seek(initialPos);
string str(buffer, buffer + readBytes);
delete [] buffer;
return str;
}
catch (...)
{
m_stream->seek(initialPos);
throw;
}
}
stream::size_type parserInputStreamAdapter::findNext
(const std::string& token, const size_type startPosition)
{
static const unsigned int BUFFER_SIZE = 4096;
// Token must not be longer than BUFFER_SIZE/2
if (token.empty() || token.length() > BUFFER_SIZE / 2)
return npos;
const size_type initialPos = getPosition();
seek(startPosition);
try
{
value_type findBuffer[BUFFER_SIZE];
value_type* findBuffer1 = findBuffer;
value_type* findBuffer2 = findBuffer + (BUFFER_SIZE / 2) * sizeof(value_type);
size_type findBufferLen = 0;
size_type findBufferOffset = 0;
// Fill in initial buffer
findBufferLen = read(findBuffer, BUFFER_SIZE * sizeof(value_type));
for (;;)
{
// Find token
for (value_type *begin = findBuffer, *end = findBuffer + findBufferLen - token.length() ;
begin <= end ; ++begin)
{
if (begin[0] == token[0] &&
(token.length() == 1 ||
memcmp(static_cast <const void *>(&begin[1]),
static_cast <const void *>(token.data() + 1),
token.length() - 1) == 0))
{
seek(initialPos);
return startPosition + findBufferOffset + (begin - findBuffer);
}
}
// Rotate buffer
memcpy(findBuffer1, findBuffer2, (BUFFER_SIZE / 2) * sizeof(value_type));
// Read more bytes
if (findBufferLen < BUFFER_SIZE && eof())
{
break;
}
else
{
const size_type bytesRead = read(findBuffer2, (BUFFER_SIZE / 2) * sizeof(value_type));
findBufferLen = (BUFFER_SIZE / 2) + bytesRead;
findBufferOffset += (BUFFER_SIZE / 2);
}
}
seek(initialPos);
}
catch (...)
{
seek(initialPos);
throw;
}
return npos;
}
} // utility
} // vmime

View File

@ -0,0 +1,95 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
namespace vmime {
namespace utility {
seekableInputStreamRegionAdapter::seekableInputStreamRegionAdapter
(ref <seekableInputStream> stream, const size_type begin, const size_type length)
: m_stream(stream), m_begin(begin), m_length(length)
{
}
bool seekableInputStreamRegionAdapter::eof() const
{
return getPosition() >= m_length;
}
void seekableInputStreamRegionAdapter::reset()
{
m_stream->seek(m_begin);
}
stream::size_type seekableInputStreamRegionAdapter::read
(value_type* const data, const size_type count)
{
if (getPosition() + count >= m_length)
{
const size_type remaining = m_length - getPosition();
return m_stream->read(data, remaining);
}
else
{
return m_stream->read(data, count);
}
}
stream::size_type seekableInputStreamRegionAdapter::skip(const size_type count)
{
if (getPosition() + count >= m_length)
{
const size_type remaining = m_length - getPosition();
m_stream->skip(remaining);
return remaining;
}
else
{
m_stream->skip(count);
return count;
}
}
stream::size_type seekableInputStreamRegionAdapter::getPosition() const
{
return m_stream->getPosition() - m_begin;
}
void seekableInputStreamRegionAdapter::seek(const size_type pos)
{
m_stream->seek(m_begin + pos);
}
} // utility
} // vmime

View File

@ -29,6 +29,9 @@ namespace vmime {
namespace utility {
const stream::size_type stream::npos = static_cast <size_type>(vmime::string::npos);
stream::size_type stream::getBlockSize()
{
return 32768; // 32 KB
@ -37,3 +40,4 @@ stream::size_type stream::getBlockSize()
} // utility
} // vmime

View File

@ -52,6 +52,35 @@ stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os)
}
stream::size_type bufferedStreamCopyRange(inputStream& is, outputStream& os,
const stream::size_type start, const stream::size_type length)
{
const stream::size_type blockSize =
std::min(is.getBlockSize(), os.getBlockSize());
is.skip(start);
std::vector <stream::value_type> vbuffer(blockSize);
stream::value_type* buffer = &vbuffer.front();
stream::size_type total = 0;
while (!is.eof() && total < length)
{
const stream::size_type remaining = std::min(length - total, blockSize);
const stream::size_type read = is.read(buffer, blockSize);
if (read != 0)
{
os.write(buffer, read);
total += read;
}
}
return total;
}
stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os,
const stream::size_type length, progressListener* progress)
{

View File

@ -241,7 +241,7 @@ const std::vector <ref <word> > word::parseMultiple(const string& buffer, const
}
void word::parse(const string& buffer, const string::size_type position,
void word::parseImpl(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
if (position + 6 < end && // 6 = "=?(.+)?(.*)?="
@ -324,7 +324,7 @@ void word::parse(const string& buffer, const string::size_type position,
}
void word::generate(utility::outputStream& os, const string::size_type maxLineLength,
void word::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
generate(os, maxLineLength, curLinePos, newLinePos, 0, NULL);
@ -743,9 +743,9 @@ void word::setBuffer(const string& buffer)
}
const std::vector <ref <const component> > word::getChildComponents() const
const std::vector <ref <component> > word::getChildComponents()
{
return std::vector <ref <const component> >();
return std::vector <ref <component> >();
}

View File

@ -33,12 +33,14 @@ VMIME_TEST_SUITE_BEGIN
VMIME_TEST_LIST_BEGIN
VMIME_TEST(testParse)
VMIME_TEST(testGenerate)
VMIME_TEST(testParseGuessBoundary)
VMIME_TEST(testParseMissingLastBoundary)
VMIME_TEST(testPrologEpilog)
VMIME_TEST(testPrologEncoding)
VMIME_TEST(testSuccessiveBoundaries)
VMIME_TEST(testGenerate7bit)
VMIME_TEST(testTextUsageForQPEncoding)
VMIME_TEST(testParseVeryBigMessage)
VMIME_TEST_LIST_END
@ -237,6 +239,93 @@ VMIME_TEST_SUITE_BEGIN
VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str());
}
void testParseGuessBoundary()
{
// Boundary is not specified in "Content-Type" field
// Parser will try to guess it from message contents.
vmime::string str =
"Content-Type: multipart/mixed"
"\r\n\r\n"
"--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
"--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
"--UNKNOWN-BOUNDARY--";
vmime::bodyPart p;
p.parse(str);
VASSERT_EQ("count", 2, p.getBody()->getPartCount());
VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
}
void testParseVeryBigMessage()
{
// When parsing from a seekable input stream, body contents should not
// be kept in memory in a "stringContentHandler" object. Instead, content
// should be accessible via a "streamContentHandler" object.
static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1";
static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1";
static const std::string BODY1_END = "END1END1";
static const unsigned int BODY1_REPEAT = 35000;
static const unsigned int BODY1_LENGTH =
BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length();
static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2";
static const unsigned int BODY2_REPEAT = 20000;
std::ostringstream oss;
oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
<< "\r\n\r\n"
<< "--MY-BOUNDARY\r\n"
<< "HEADER1\r\n"
<< "\r\n";
oss << BODY1_BEGIN;
for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i)
oss << BODY1_LINE;
oss << BODY1_END;
oss << "\r\n"
<< "--MY-BOUNDARY\r\n"
<< "HEADER2\r\n"
<< "\r\n";
for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i)
oss << BODY2_LINE;
oss << "\r\n"
<< "--MY-BOUNDARY--\r\n";
vmime::ref <vmime::utility::inputStreamStringAdapter> is =
vmime::create <vmime::utility::inputStreamStringAdapter>(oss.str());
vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
msg->parse(is, oss.str().length());
vmime::ref <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody();
vmime::ref <const vmime::contentHandler> body1Cts = body1->getContents();
vmime::ref <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody();
vmime::ref <const vmime::contentHandler> body2Cts = body2->getContents();
vmime::string body1CtsExtracted;
vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted);
body1Cts->extract(body1CtsExtractStream);
VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength());
VASSERT("1.2", body1Cts.dynamicCast <const vmime::streamContentHandler>() != NULL);
VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length());
VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length()));
VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length()));
VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength());
VASSERT("2.2", body2Cts.dynamicCast <const vmime::streamContentHandler>() != NULL);
}
VMIME_TEST_SUITE_END

View File

@ -56,7 +56,7 @@ public:
addressList& operator=(const addressList& other);
addressList& operator=(const mailboxList& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Add a address at the end of the list.
@ -163,14 +163,20 @@ private:
std::vector <ref <address> > m_list;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -278,7 +278,7 @@ public:
void copyFrom(const component& other);
body& operator=(const body& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
private:
@ -299,14 +299,20 @@ private:
void initNewPart(ref <bodyPart> part);
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(ref <utility::parserInputStreamAdapter> parser,
const utility::stream::size_type position,
const utility::stream::size_type end,
utility::stream::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -89,7 +89,7 @@ public:
void copyFrom(const component& other);
bodyPart& operator=(const bodyPart& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
private:
@ -98,14 +98,20 @@ private:
weak_ref <bodyPart> m_parent;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(ref <utility::parserInputStreamAdapter> parser,
const utility::stream::size_type position,
const utility::stream::size_type end,
utility::stream::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -62,7 +62,7 @@ public:
bool operator==(const charset& value) const;
bool operator!=(const charset& value) const;
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Gets the recommended encoding for this charset.
* Note: there may be no recommended encoding.
@ -117,14 +117,20 @@ private:
string m_name;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -27,6 +27,8 @@
#include "vmime/base.hpp"
#include "vmime/utility/inputStream.hpp"
#include "vmime/utility/seekableInputStream.hpp"
#include "vmime/utility/parserInputStreamAdapter.hpp"
#include "vmime/utility/outputStream.hpp"
@ -51,6 +53,12 @@ public:
*/
void parse(const string& buffer);
/** Parse RFC-822/MIME data for this component. If stream is not seekable,
* or if length is not specified, entire contents of the stream will
* be loaded into memory before parsing.
*/
void parse(ref <utility::inputStream> inputStream, const utility::stream::size_type length);
/** Parse RFC-822/MIME data for this component.
*
* @param buffer input buffer
@ -58,7 +66,26 @@ public:
* @param end end position in the input buffer
* @param newPosition will receive the new position in the input buffer
*/
virtual void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL) = 0;
void parse
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
/** Parse RFC-822/MIME data for this component. If stream is not seekable,
* or if end position is not specified, entire contents of the stream will
* be loaded into memory before parsing.
*
* @param inputStream stream from which to read data
* @param position current position in the input stream
* @param end end position in the input stream
* @param newPosition will receive the new position in the input stream
*/
void parse
(ref <utility::inputStream> inputStream,
const utility::stream::size_type position,
const utility::stream::size_type end,
utility::stream::size_type* newPosition = NULL);
/** Generate RFC-2822/MIME data for this component.
*
@ -68,16 +95,35 @@ public:
* @param curLinePos length of the current line in the output buffer
* @return generated data
*/
const string generate(const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0) const;
virtual const string generate
(const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0) const;
/** Generate RFC-2822/MIME data for this component.
*
* @param os output stream
* @param outputStream output stream
* @param maxLineLength maximum line length for output
* @param curLinePos length of the current line in the output buffer
* @param newLinePos will receive the new line position (length of the last line written)
*/
virtual void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const = 0;
virtual void generate
(utility::outputStream& outputStream,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
/** Generate RFC-2822/MIME data for this component.
*
* @param outputStream output stream
* @param maxLineLength maximum line length for output
* @param curLinePos length of the current line in the output buffer
* @param newLinePos will receive the new line position (length of the last line written)
*/
virtual void generate
(ref <utility::outputStream> outputStream,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
/** Clone this component.
*
@ -95,41 +141,56 @@ public:
virtual void copyFrom(const component& other) = 0;
/** Return the start position of this component in the
* parsed message contents.
* parsed message contents. Use for debugging only.
*
* @return start position in parsed buffer
* or 0 if this component has not been parsed
*/
string::size_type getParsedOffset() const;
utility::stream::size_type getParsedOffset() const;
/** Return the length of this component in the
* parsed message contents.
* parsed message contents. Use for debugging only.
*
* @return length of the component in parsed buffer
* or 0 if this component has not been parsed
*/
string::size_type getParsedLength() const;
utility::stream::size_type getParsedLength() const;
/** Return the list of children of this component.
*
* @return list of child components
*/
const std::vector <ref <component> > getChildComponents();
/** Return the list of children of this component (const version).
*
* @return list of child components
*/
virtual const std::vector <ref <const component> > getChildComponents() const = 0;
virtual const std::vector <ref <component> > getChildComponents() = 0;
protected:
void setParsedBounds(const string::size_type start, const string::size_type end);
void setParsedBounds(const utility::stream::size_type start, const utility::stream::size_type end);
// AT LEAST ONE of these parseImpl() functions MUST be implemented in derived class
virtual void parseImpl
(ref <utility::parserInputStreamAdapter> parser,
const utility::stream::size_type position,
const utility::stream::size_type end,
utility::stream::size_type* newPosition = NULL);
virtual void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
virtual void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const = 0;
private:
string::size_type m_parsedOffset;
string::size_type m_parsedLength;
void offsetParsedBounds(const utility::stream::size_type offset);
utility::stream::size_type m_parsedOffset;
utility::stream::size_type m_parsedLength;
};

View File

@ -63,7 +63,7 @@ public:
void copyFrom(const component& other);
contentDisposition& operator=(const contentDisposition& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
contentDisposition& operator=(const string& name);
@ -75,14 +75,20 @@ private:
string m_name;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -237,16 +237,22 @@ public:
// Current date and time
static const datetime now();
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -50,7 +50,7 @@ public:
void copyFrom(const component& other);
disposition& operator=(const disposition& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Set the disposition action mode.
@ -134,14 +134,20 @@ private:
std::vector <string> m_modifiers;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -93,7 +93,7 @@ public:
bool operator==(const encoding& value) const;
bool operator!=(const encoding& value) const;
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Decide which encoding to use based on the specified data.
*
@ -141,14 +141,20 @@ private:
*/
static const encoding decideImpl(const string::const_iterator begin, const string::const_iterator end);
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -220,7 +220,7 @@ public:
void copyFrom(const component& other);
header& operator=(const header& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
private:
@ -251,14 +251,20 @@ private:
string m_name;
};
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -59,7 +59,7 @@ public:
void copyFrom(const component& other);
headerField& operator=(const headerField& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Sets the name of this field.
*
@ -118,15 +118,26 @@ public:
void setValue(const string& value);
using component::parse;
using component::generate;
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
protected:
static ref <headerField> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
static ref <headerField> parseNext
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
string m_name;

View File

@ -85,7 +85,7 @@ public:
void clear();
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
bool isGroup() const;
@ -101,8 +101,17 @@ public:
using address::generate;
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -52,7 +52,7 @@ public:
ref <component> clone() const;
mailboxGroup& operator=(const component& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Return the name of the group.
*
@ -165,14 +165,20 @@ private:
text m_name;
std::vector <ref <mailbox> > m_list;
public:
using address::parse;
using address::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -51,7 +51,7 @@ public:
void copyFrom(const component& other);
mailboxList& operator=(const mailboxList& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Add a mailbox at the end of the list.
*
@ -155,14 +155,20 @@ private:
addressList m_list;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -55,7 +55,7 @@ public:
void copyFrom(const component& other);
mediaType& operator=(const mediaType& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Return the media type.
* See the constants in vmime::mediaTypes.
@ -97,14 +97,18 @@ protected:
string m_type;
string m_subType;
public:
using component::parse;
using component::generate;
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -43,12 +43,25 @@ public:
message();
// Component parsing & assembling
void generate(utility::outputStream& os, const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
public:
const string generate(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0) const;
// Override default generate() functions so that we can change
// the default 'maxLineLength' value
void generate
(utility::outputStream& os,
const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(),
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
void parse(const string& buffer);
const string generate
(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(),
const string::size_type curLinePos = 0) const;
void generate
(ref <utility::outputStream> os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -97,23 +97,27 @@ public:
void copyFrom(const component& other);
messageId& operator=(const messageId& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
private:
string m_left;
string m_right;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
protected:
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
/** Parse a message-id from an input buffer.
*
@ -123,7 +127,11 @@ protected:
* @param newPosition will receive the new position in the input buffer
* @return a new message-id object, or null if no more message-id can be parsed from the input buffer
*/
static ref <messageId> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);
static ref <messageId> parseNext
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition);
};

View File

@ -49,7 +49,7 @@ public:
void copyFrom(const component& other);
messageIdSequence& operator=(const messageIdSequence& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Add a message-id at the end of the list.
@ -148,14 +148,20 @@ private:
std::vector <ref <messageId> > m_list;
public:
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -67,7 +67,7 @@ public:
void copyFrom(const component& other);
parameter& operator=(const parameter& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Return the name of this parameter.
*
@ -104,7 +104,7 @@ public:
const T getValueAs() const
{
T ret;
ret.parse(m_value.getBuffer());
ret.parse(m_value->getBuffer());
return ret;
}
@ -122,11 +122,19 @@ public:
void setValue(const word& value);
using component::parse;
using component::generate;
protected:
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
private:
@ -134,7 +142,7 @@ private:
string m_name;
word m_value;
ref <word> m_value;
};

View File

@ -172,19 +172,25 @@ public:
*/
const std::vector <ref <parameter> > getParameterList();
const std::vector <ref <component> > getChildComponents();
private:
std::vector <ref <parameter> > m_params;
public:
protected:
using headerField::parse;
using headerField::generate;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
const std::vector <ref <const component> > getChildComponents() const;
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -45,6 +45,10 @@ public:
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
static bool isSpaceOrTab(const char_t c)
{
return (c == ' ' || c == '\t');
}
static bool isDigit(const char_t c)
{

View File

@ -76,21 +76,26 @@ public:
ref <component> clone() const;
path& operator=(const path& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
protected:
string m_localPart;
string m_domain;
public:
using component::parse;
using component::generate;
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -26,6 +26,7 @@
#include "vmime/utility/file.hpp"
#include "vmime/utility/seekableInputStream.hpp"
#if VMIME_HAVE_FILESYSTEM_FEATURES
@ -57,7 +58,7 @@ private:
class posixFileReaderInputStream : public vmime::utility::inputStream
class posixFileReaderInputStream : public vmime::utility::seekableInputStream
{
public:
@ -72,6 +73,9 @@ public:
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:
const vmime::utility::file::path m_path;

View File

@ -26,6 +26,7 @@
#include "vmime/utility/file.hpp"
#include "vmime/utility/seekableInputStream.hpp"
#include <windows.h>
@ -157,6 +158,8 @@ public:
void reset();
size_type read(value_type* const data, const size_type count);
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:

View File

@ -51,7 +51,7 @@ public:
void copyFrom(const component& other);
relay& operator=(const relay& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
const string& getFrom() const;
void setFrom(const string& from);
@ -85,13 +85,19 @@ private:
datetime m_date;
public:
protected:
using component::parse;
using component::generate;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
};

View File

@ -58,7 +58,7 @@ public:
text& operator=(const component& other);
text& operator=(const text& other);
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
/** Add a word at the end of the list.
*
@ -226,13 +226,20 @@ public:
*/
static text* decodeAndUnfold(const string& in, text* generateInExisting);
using component::parse;
using component::generate;
protected:
// Component parsing & assembling
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
private:

View File

@ -25,7 +25,7 @@
#define VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
#include "vmime/utility/inputStream.hpp"
#include "vmime/utility/seekableInputStream.hpp"
#include <istream>
@ -37,7 +37,7 @@ namespace utility {
/** An adapter class for C++ standard input streams.
*/
class inputStreamAdapter : public inputStream
class inputStreamAdapter : public seekableInputStream
{
public:
@ -49,6 +49,8 @@ public:
void reset();
size_type read(value_type* const data, const size_type count);
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:

View File

@ -25,7 +25,7 @@
#define VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
#include "vmime/utility/inputStream.hpp"
#include "vmime/utility/seekableInputStream.hpp"
namespace vmime {
@ -35,7 +35,7 @@ namespace utility {
/** An adapter class for reading from an array of bytes.
*/
class inputStreamByteBufferAdapter : public inputStream
class inputStreamByteBufferAdapter : public seekableInputStream
{
public:
@ -45,6 +45,8 @@ public:
void reset();
size_type read(value_type* const data, const size_type count);
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:

View File

@ -25,7 +25,7 @@
#define VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
#include "vmime/utility/inputStream.hpp"
#include "vmime/utility/seekableInputStream.hpp"
namespace vmime {
@ -35,7 +35,7 @@ namespace utility {
/** An adapter class for string input.
*/
class inputStreamStringAdapter : public inputStream
class inputStreamStringAdapter : public seekableInputStream
{
public:
@ -46,6 +46,8 @@ public:
void reset();
size_type read(value_type* const data, const size_type count);
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:

View File

@ -25,7 +25,7 @@
#define VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED
#include "vmime/utility/inputStream.hpp"
#include "vmime/utility/seekableInputStream.hpp"
namespace vmime {
@ -38,7 +38,7 @@ class stringProxy;
/** An adapter class for stringProxy input.
*/
class inputStreamStringProxyAdapter : public inputStream
class inputStreamStringProxyAdapter : public seekableInputStream
{
public:
@ -50,6 +50,8 @@ public:
void reset();
size_type read(value_type* const data, const size_type count);
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:

View File

@ -0,0 +1,173 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#ifndef VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
#define VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
#include "vmime/utility/seekableInputStream.hpp"
#include <cstring>
namespace vmime {
namespace utility {
/** An adapter class used for parsing from an input stream.
*/
class parserInputStreamAdapter : public seekableInputStream
{
public:
/** @param is input stream to wrap
*/
parserInputStreamAdapter(ref <seekableInputStream> inputStream);
ref <seekableInputStream> getUnderlyingStream();
bool eof() const;
void reset();
size_type read(value_type* const data, const size_type count);
void seek(const size_type pos)
{
m_stream->seek(pos);
}
size_type skip(const size_type count)
{
return m_stream->skip(count);
}
size_type getPosition() const
{
return m_stream->getPosition();
}
/** Get the byte at the current position without updating the
* current position.
*
* @return byte at the current position
*/
value_type peekByte() const
{
const size_type initialPos = m_stream->getPosition();
try
{
value_type buffer[1];
const size_type readBytes = m_stream->read(buffer, 1);
m_stream->seek(initialPos);
return (readBytes == 1 ? buffer[0] : 0);
}
catch (...)
{
m_stream->seek(initialPos);
throw;
}
}
/** Get the byte at the current position and advance current
* position by one byte.
*
* @return byte at the current position
*/
value_type getByte()
{
value_type buffer[1];
const size_type readBytes = m_stream->read(buffer, 1);
return (readBytes == 1 ? buffer[0] : 0);
}
/** Check whether the bytes following the current position match
* the specified bytes. Position is not updated.
*
* @param bytes bytes to compare
* @param length number of bytes
* @return true if the next bytes match the pattern, false otherwise
*/
bool matchBytes(const value_type* bytes, const size_type length) const
{
const size_type initialPos = m_stream->getPosition();
try
{
value_type buffer[32];
const size_type readBytes = m_stream->read(buffer, length);
m_stream->seek(initialPos);
return readBytes == length &&
::memcmp(bytes, buffer, length) == 0;
}
catch (...)
{
m_stream->seek(initialPos);
throw;
}
}
const string extract(const size_type begin, const size_type end) const;
/** Skips bytes matching a predicate from the current position.
* The current position is updated to the next following byte
* which does not match the predicate.
*
* @param pred predicate
* @param endPosition stop at this position (or at end of the stream,
* whichever comes first)
* @return number of bytes skipped
*/
template <typename PREDICATE>
size_type skipIf(PREDICATE pred, const size_type endPosition)
{
const size_type initialPos = getPosition();
size_type pos = initialPos;
while (!m_stream->eof() && pos < endPosition && pred(getByte()))
++pos;
m_stream->seek(pos);
return pos - initialPos;
}
size_type findNext(const std::string& token, const size_type startPosition = 0);
private:
mutable ref <seekableInputStream> m_stream;
};
} // utility
} // vmime
#endif // VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED

View File

@ -0,0 +1,64 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
#define VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
#include "vmime/utility/inputStream.hpp"
namespace vmime {
namespace utility {
/** An input stream that allows seeking within the input.
*/
class seekableInputStream : public inputStream
{
public:
/** Returns the current position in this stream.
*
* @return the offset from the beginning of the stream, in bytes,
* at which the next read occurs
*/
virtual size_type getPosition() const = 0;
/** Sets the position, measured from the beginning of this stream,
* at which the next read occurs.
*
* @param pos the offset position, measured in bytes from the
* beginning of the stream, at which to set the stream pointer.
*/
virtual void seek(const size_type pos) = 0;
};
} // utility
} // vmime
#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED

View File

@ -0,0 +1,71 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
#define VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
#include "vmime/utility/seekableInputStream.hpp"
namespace vmime {
namespace utility {
/** An adapter for reading a limited region of a seekable input stream.
*/
class seekableInputStreamRegionAdapter : public seekableInputStream
{
public:
/** Creates a new adapter for a seekableInputStream.
*
* @param stream source stream
* @param begin start position in source stream
* @param length region length in source stream
*/
seekableInputStreamRegionAdapter(ref <seekableInputStream> stream,
const size_type begin, const size_type length);
bool eof() const;
void reset();
size_type read(value_type* const data, const size_type count);
size_type skip(const size_type count);
size_type getPosition() const;
void seek(const size_type pos);
private:
ref <seekableInputStream> m_stream;
size_type m_begin;
size_type m_length;
};
} // utility
} // vmime
#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED

View File

@ -54,6 +54,10 @@ public:
*/
typedef string::size_type size_type;
/** Constant value with the greatest possible value for an element of type size_type.
*/
static const size_type npos;
/** Return the preferred maximum block size when reading
* from or writing to this stream.
*

View File

@ -44,6 +44,19 @@ namespace utility {
stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os);
/** Copy data from one stream into another stream using a buffered method
* and copying only a specified range of data.
*
* @param is input stream (source data)
* @param os output stream (destination for data)
* @param start number of bytes to ignore before starting copying
* @param length maximum number of bytes to copy
* @return number of bytes copied
*/
stream::size_type bufferedStreamCopyRange(inputStream& is, outputStream& os,
const stream::size_type start, const stream::size_type length);
/** Copy data from one stream into another stream using a buffered method
* and notify progress state of the operation.
*

View File

@ -128,21 +128,52 @@ public:
#endif
using component::parse;
protected:
void parseImpl
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition = NULL);
void generateImpl
(utility::outputStream& os,
const string::size_type maxLineLength = lineLengthLimits::infinite,
const string::size_type curLinePos = 0,
string::size_type* newLinePos = NULL) const;
public:
using component::generate;
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
#ifndef VMIME_BUILDING_DOC
void generate
(utility::outputStream& os,
const string::size_type maxLineLength,
const string::size_type curLinePos,
string::size_type* newLinePos,
const int flags,
generatorState* state) const;
#endif
void generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos, const int flags, generatorState* state) const;
const std::vector <ref <const component> > getChildComponents() const;
const std::vector <ref <component> > getChildComponents();
private:
static ref <word> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition, bool prevIsEncoded, bool* isEncoded, bool isFirst);
static ref <word> parseNext
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition,
bool prevIsEncoded,
bool* isEncoded,
bool isFirst);
static const std::vector <ref <word> > parseMultiple(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);
static const std::vector <ref <word> > parseMultiple
(const string& buffer,
const string::size_type position,
const string::size_type end,
string::size_type* newPosition);
// The "m_buffer" of this word holds the data, and this data is encoded