aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--SConstruct3
-rw-r--r--src/addressList.cpp8
-rw-r--r--src/body.cpp220
-rw-r--r--src/bodyPart.cpp17
-rw-r--r--src/charset.cpp8
-rw-r--r--src/component.cpp137
-rw-r--r--src/contentDisposition.cpp8
-rw-r--r--src/dateTime.cpp8
-rw-r--r--src/disposition.cpp8
-rw-r--r--src/encoding.cpp8
-rw-r--r--src/header.cpp8
-rw-r--r--src/headerField.cpp8
-rw-r--r--src/mailbox.cpp8
-rw-r--r--src/mailboxGroup.cpp8
-rw-r--r--src/mailboxList.cpp6
-rw-r--r--src/mediaType.cpp8
-rw-r--r--src/message.cpp9
-rw-r--r--src/messageId.cpp8
-rw-r--r--src/messageIdSequence.cpp8
-rw-r--r--src/parameter.cpp40
-rw-r--r--src/parameterizedHeaderField.cpp12
-rw-r--r--src/path.cpp12
-rw-r--r--src/platforms/posix/posixFile.cpp20
-rw-r--r--src/platforms/windows/windowsFile.cpp18
-rw-r--r--src/relay.cpp8
-rw-r--r--src/streamContentHandler.cpp4
-rw-r--r--src/text.cpp8
-rw-r--r--src/utility/inputStreamAdapter.cpp12
-rw-r--r--src/utility/inputStreamByteBufferAdapter.cpp13
-rw-r--r--src/utility/inputStreamStringAdapter.cpp13
-rw-r--r--src/utility/inputStreamStringProxyAdapter.cpp13
-rw-r--r--src/utility/parserInputStreamAdapter.cpp162
-rw-r--r--src/utility/seekableInputStreamRegionAdapter.cpp95
-rw-r--r--src/utility/stream.cpp4
-rw-r--r--src/utility/streamUtils.cpp29
-rw-r--r--src/word.cpp8
-rw-r--r--tests/parser/bodyPartTest.cpp89
-rw-r--r--vmime/addressList.hpp20
-rw-r--r--vmime/body.hpp20
-rw-r--r--vmime/bodyPart.hpp20
-rw-r--r--vmime/charset.hpp20
-rw-r--r--vmime/component.hpp97
-rw-r--r--vmime/contentDisposition.hpp20
-rw-r--r--vmime/dateTime.hpp20
-rw-r--r--vmime/disposition.hpp20
-rw-r--r--vmime/encoding.hpp20
-rw-r--r--vmime/header.hpp20
-rw-r--r--vmime/headerField.hpp25
-rw-r--r--vmime/mailbox.hpp15
-rw-r--r--vmime/mailboxGroup.hpp20
-rw-r--r--vmime/mailboxList.hpp20
-rw-r--r--vmime/mediaType.hpp20
-rw-r--r--vmime/message.hpp23
-rw-r--r--vmime/messageId.hpp28
-rw-r--r--vmime/messageIdSequence.hpp20
-rw-r--r--vmime/parameter.hpp22
-rw-r--r--vmime/parameterizedHeaderField.hpp22
-rw-r--r--vmime/parserHelpers.hpp4
-rw-r--r--vmime/path.hpp19
-rw-r--r--vmime/platforms/posix/posixFile.hpp6
-rw-r--r--vmime/platforms/windows/windowsFile.hpp3
-rw-r--r--vmime/relay.hpp18
-rw-r--r--vmime/text.hpp19
-rw-r--r--vmime/utility/inputStreamAdapter.hpp6
-rw-r--r--vmime/utility/inputStreamByteBufferAdapter.hpp6
-rw-r--r--vmime/utility/inputStreamStringAdapter.hpp6
-rw-r--r--vmime/utility/inputStreamStringProxyAdapter.hpp6
-rw-r--r--vmime/utility/parserInputStreamAdapter.hpp173
-rw-r--r--vmime/utility/seekableInputStream.hpp64
-rw-r--r--vmime/utility/seekableInputStreamRegionAdapter.hpp71
-rw-r--r--vmime/utility/stream.hpp4
-rw-r--r--vmime/utility/streamUtils.hpp13
-rw-r--r--vmime/word.hpp49
74 files changed, 1643 insertions, 378 deletions
diff --git a/ChangeLog b/ChangeLog
index 8fdcdb05..1b5b2cf7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,12 @@
VERSION 0.9.2svn
================
+2012-04-16 Vincent Richard <[email protected]>
+
+ * 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 <[email protected]>
* Started version 0.9.2.
diff --git a/SConstruct b/SConstruct
index ea5c4eb1..2690172e 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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',
diff --git a/src/addressList.cpp b/src/addressList.cpp
index 31a2a3d8..f06460d3 100644
--- a/src/addressList.cpp
+++ b/src/addressList.cpp
@@ -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);
diff --git a/src/body.cpp b/src/body.cpp
index 9d7d57f9..732fa8b5 100644
--- a/src/body.cpp
+++ b/src/body.cpp
@@ -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;
+
+ parser->seek(pos);
+
+ if (pos + 2 < end && parser->matchBytes("--", 2))
+ {
+ pos += 2;
+ }
+ else
+ {
+ pos = parser->findNext("\n--", position);
- if ((pos != string::npos) && (pos < end))
+ if ((pos != utility::stream::npos) && (pos + 3 < end))
+ pos += 3; // skip \n--
+ }
+
+ if ((pos != utility::stream::npos) && (pos < end))
{
- pos += 3;
+ parser->seek(pos);
- const string::size_type start = 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])));
- char_t c = buffer[pos];
- string::size_type length = 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;
-
- boundary = string(buffer.begin() + start,
- buffer.begin() + pos);
+ while (boundaryLen != 0 &&
+ parserHelpers::isSpace(boundaryBytes[boundaryLen - 1]))
+ {
+ boundaryLen--;
+ }
+
+ 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);
-
- if (pos == string::npos ||
- ((pos == 0 || buffer[pos - 1] == '\n') &&
- (buffer[pos + boundarySep.length()] == '\r' ||
- buffer[pos + boundarySep.length()] == '\n' ||
- buffer[pos + boundarySep.length()] == '-'
- )
- )
- )
+ pos = parser->findNext(boundarySep, pos);
+
+ 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);
-
- if (pos == string::npos ||
- ((pos == 0 || buffer[pos - 1] == '\n') &&
- (buffer[pos + boundarySep.length()] == '\r' ||
- buffer[pos + boundarySep.length()] == '\n' ||
- buffer[pos + boundarySep.length()] == '-'
- )
- )
- )
+ pos = parser->findNext(boundarySep, pos);
+
+ 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);
diff --git a/src/bodyPart.cpp b/src/bodyPart.cpp
index 7d60461e..522cbb23 100644
--- a/src/bodyPart.cpp
+++ b/src/bodyPart.cpp
@@ -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);
diff --git a/src/charset.cpp b/src/charset.cpp
index 0fda4506..705664f4 100644
--- a/src/charset.cpp
+++ b/src/charset.cpp
@@ -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> >();
}
diff --git a/src/component.cpp b/src/component.cpp
index 139cf664..e93aacf3 100644
--- a/src/component.cpp
+++ b/src/component.cpp
@@ -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();
-
- std::vector <ref <component> > list;
-
- const std::vector <ref <const component> >::size_type count = constList.size();
+} // vmime
- list.resize(count);
-
- for (std::vector <ref <const component> >::size_type i = 0 ; i < count ; ++i)
- list[i] = constList[i].constCast <component>();
-
- return (list);
-}
-
-
-}
diff --git a/src/contentDisposition.cpp b/src/contentDisposition.cpp
index 0ab7c458..253dbba5 100644
--- a/src/contentDisposition.cpp
+++ b/src/contentDisposition.cpp
@@ -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> >();
}
diff --git a/src/dateTime.cpp b/src/dateTime.cpp
index 089a9006..0d97b2f6 100644
--- a/src/dateTime.cpp
+++ b/src/dateTime.cpp
@@ -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> >();
}
diff --git a/src/disposition.cpp b/src/disposition.cpp
index b8059a77..24a45798 100644
--- a/src/disposition.cpp
+++ b/src/disposition.cpp
@@ -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;
diff --git a/src/encoding.cpp b/src/encoding.cpp
index 5d99ab63..343a8223 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -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> >();
}
diff --git a/src/header.cpp b/src/header.cpp
index 443aab8b..fcdca2c9 100644
--- a/src/header.cpp
+++ b/src/header.cpp
@@ -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);
diff --git a/src/headerField.cpp b/src/headerField.cpp
index d1d42368..a8460aaa 100644
--- a/src/headerField.cpp
+++ b/src/headerField.cpp
@@ -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);
diff --git a/src/mailbox.cpp b/src/mailbox.cpp
index fea74797..dfdccad7 100644
--- a/src/mailbox.cpp
+++ b/src/mailbox.cpp
@@ -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> >();
}
diff --git a/src/mailboxGroup.cpp b/src/mailboxGroup.cpp
index 94f7ba69..c37444a0 100644
--- a/src/mailboxGroup.cpp
+++ b/src/mailboxGroup.cpp
@@ -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);
diff --git a/src/mailboxList.cpp b/src/mailboxList.cpp
index 0023d9d0..f87fb48d 100644
--- a/src/mailboxList.cpp
+++ b/src/mailboxList.cpp
@@ -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);
diff --git a/src/mediaType.cpp b/src/mediaType.cpp
index 725f9338..627b2768 100644
--- a/src/mediaType.cpp
+++ b/src/mediaType.cpp
@@ -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> >();
}
diff --git a/src/message.cpp b/src/message.cpp
index 1b4f0867..3fa9b6a3 100644
--- a/src/message.cpp
+++ b/src/message.cpp
@@ -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);
}
diff --git a/src/messageId.cpp b/src/messageId.cpp
index 961fb637..1f4b1863 100644
--- a/src/messageId.cpp
+++ b/src/messageId.cpp
@@ -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> >();
}
diff --git a/src/messageIdSequence.cpp b/src/messageIdSequence.cpp
index 08103d07..0a5c9a01 100644
--- a/src/messageIdSequence.cpp
+++ b/src/messageIdSequence.cpp
@@ -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;
diff --git a/src/parameter.cpp b/src/parameter.cpp
index ccbe1a5b..58d9a3eb 100644
--- a/src/parameter.cpp
+++ b/src/parameter.cpp
@@ -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;
}
diff --git a/src/parameterizedHeaderField.cpp b/src/parameterizedHeaderField.cpp
index 464990e9..756d02f2 100644
--- a/src/parameterizedHeaderField.cpp
+++ b/src/parameterizedHeaderField.cpp
@@ -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);
diff --git a/src/path.cpp b/src/path.cpp
index 37a40908..d92bb0a6 100644
--- a/src/path.cpp
+++ b/src/path.cpp
@@ -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())
{
diff --git a/src/platforms/posix/posixFile.cpp b/src/platforms/posix/posixFile.cpp
index ec529eb6..4087a21f 100644
--- a/src/platforms/posix/posixFile.cpp
+++ b/src/platforms/posix/posixFile.cpp
@@ -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
diff --git a/src/platforms/windows/windowsFile.cpp b/src/platforms/windows/windowsFile.cpp
index 624612af..5da786e5 100644
--- a/src/platforms/windows/windowsFile.cpp
+++ b/src/platforms/windows/windowsFile.cpp
@@ -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)
{
diff --git a/src/relay.cpp b/src/relay.cpp
index 5cd454fc..97f793db 100644
--- a/src/relay.cpp
+++ b/src/relay.cpp
@@ -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> >();
}
diff --git a/src/streamContentHandler.cpp b/src/streamContentHandler.cpp
index 89a36b4f..14837d26 100644
--- a/src/streamContentHandler.cpp
+++ b/src/streamContentHandler.cpp
@@ -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;
}
diff --git a/src/text.cpp b/src/text.cpp
index 66c3b353..91b81e1b 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -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);
diff --git a/src/utility/inputStreamAdapter.cpp b/src/utility/inputStreamAdapter.cpp
index b44b0841..441307b5 100644
--- a/src/utility/inputStreamAdapter.cpp
+++ b/src/utility/inputStreamAdapter.cpp
@@ -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
diff --git a/src/utility/inputStreamByteBufferAdapter.cpp b/src/utility/inputStreamByteBufferAdapter.cpp
index 92e779fe..907f1eec 100644
--- a/src/utility/inputStreamByteBufferAdapter.cpp
+++ b/src/utility/inputStreamByteBufferAdapter.cpp
@@ -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
diff --git a/src/utility/inputStreamStringAdapter.cpp b/src/utility/inputStreamStringAdapter.cpp
index 31c9fdaf..9b8fb0c7 100644
--- a/src/utility/inputStreamStringAdapter.cpp
+++ b/src/utility/inputStreamStringAdapter.cpp
@@ -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
diff --git a/src/utility/inputStreamStringProxyAdapter.cpp b/src/utility/inputStreamStringProxyAdapter.cpp
index 5e4b60b9..feecddd5 100644
--- a/src/utility/inputStreamStringProxyAdapter.cpp
+++ b/src/utility/inputStreamStringProxyAdapter.cpp
@@ -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
diff --git a/src/utility/parserInputStreamAdapter.cpp b/src/utility/parserInputStreamAdapter.cpp
new file mode 100644
index 00000000..7a38ef1b
--- /dev/null
+++ b/src/utility/parserInputStreamAdapter.cpp
@@ -0,0 +1,162 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2012 Vincent Richard <[email protected]>
+//
+// 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
+
diff --git a/src/utility/seekableInputStreamRegionAdapter.cpp b/src/utility/seekableInputStreamRegionAdapter.cpp
new file mode 100644
index 00000000..348618c0
--- /dev/null
+++ b/src/utility/seekableInputStreamRegionAdapter.cpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2012 Vincent Richard <[email protected]>
+//
+// 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
+
diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp
index 1c940c2a..67c1f330 100644
--- a/src/utility/stream.cpp
+++ b/src/utility/stream.cpp
@@ -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
+
diff --git a/src/utility/streamUtils.cpp b/src/utility/streamUtils.cpp
index f1d3b9de..f7ea62f3 100644
--- a/src/utility/streamUtils.cpp
+++ b/src/utility/streamUtils.cpp
@@ -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)
{
diff --git a/src/word.cpp b/src/word.cpp
index 79060a18..2876ddfb 100644
--- a/src/word.cpp
+++ b/src/word.cpp
@@ -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> >();
}
diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp
index 9d51262a..deb4b9c5 100644
--- a/tests/parser/bodyPartTest.cpp
+++ b/tests/parser/bodyPartTest.cpp
@@ -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
diff --git a/vmime/addressList.hpp b/vmime/addressList.hpp
index 2e537c05..9dc283c7 100644
--- a/vmime/addressList.hpp
+++ b/vmime/addressList.hpp
@@ -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;
};
diff --git a/vmime/body.hpp b/vmime/body.hpp
index 9e83d6b5..bd5bbb92 100644
--- a/vmime/body.hpp
+++ b/vmime/body.hpp
@@ -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;
};
diff --git a/vmime/bodyPart.hpp b/vmime/bodyPart.hpp
index aa0f0408..5f36d903 100644
--- a/vmime/bodyPart.hpp
+++ b/vmime/bodyPart.hpp
@@ -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;
};
diff --git a/vmime/charset.hpp b/vmime/charset.hpp
index 5f5e8e58..26abb4f8 100644
--- a/vmime/charset.hpp
+++ b/vmime/charset.hpp
@@ -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;
};
diff --git a/vmime/component.hpp b/vmime/component.hpp
index 12b04060..5e6f393d 100644
--- a/vmime/component.hpp
+++ b/vmime/component.hpp
@@ -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;
};
diff --git a/vmime/contentDisposition.hpp b/vmime/contentDisposition.hpp
index 9d1749be..abd2e1a4 100644
--- a/vmime/contentDisposition.hpp
+++ b/vmime/contentDisposition.hpp
@@ -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;
};
diff --git a/vmime/dateTime.hpp b/vmime/dateTime.hpp
index 8e996409..053f4a69 100644
--- a/vmime/dateTime.hpp
+++ b/vmime/dateTime.hpp
@@ -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;
};
diff --git a/vmime/disposition.hpp b/vmime/disposition.hpp
index 05bfca2b..7bdc832f 100644
--- a/vmime/disposition.hpp
+++ b/vmime/disposition.hpp
@@ -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;
};
diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp
index 42f5246d..4322b298 100644
--- a/vmime/encoding.hpp
+++ b/vmime/encoding.hpp
@@ -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;
};
diff --git a/vmime/header.hpp b/vmime/header.hpp
index 95a93267..ed555b0c 100644
--- a/vmime/header.hpp
+++ b/vmime/header.hpp
@@ -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;
};
diff --git a/vmime/headerField.hpp b/vmime/headerField.hpp
index 50494c94..61e01eee 100644
--- a/vmime/headerField.hpp
+++ b/vmime/headerField.hpp
@@ -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;
+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;
-protected:
- static ref <headerField> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+ 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;
diff --git a/vmime/mailbox.hpp b/vmime/mailbox.hpp
index 2072be86..2099355d 100644
--- a/vmime/mailbox.hpp
+++ b/vmime/mailbox.hpp
@@ -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;
};
diff --git a/vmime/mailboxGroup.hpp b/vmime/mailboxGroup.hpp
index 0061d5b4..14331410 100644
--- a/vmime/mailboxGroup.hpp
+++ b/vmime/mailboxGroup.hpp
@@ -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;
};
diff --git a/vmime/mailboxList.hpp b/vmime/mailboxList.hpp
index 11e4e798..1b480c17 100644
--- a/vmime/mailboxList.hpp
+++ b/vmime/mailboxList.hpp
@@ -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;
};
diff --git a/vmime/mediaType.hpp b/vmime/mediaType.hpp
index 658b21fe..18182f0c 100644
--- a/vmime/mediaType.hpp
+++ b/vmime/mediaType.hpp
@@ -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;
};
diff --git a/vmime/message.hpp b/vmime/message.hpp
index f3be2294..9767564d 100644
--- a/vmime/message.hpp
+++ b/vmime/message.hpp
@@ -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;
-
- const string generate(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0) const;
+public:
- void parse(const string& buffer);
+ // 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;
+
+ 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;
};
diff --git a/vmime/messageId.hpp b/vmime/messageId.hpp
index 3686b11c..ac408e63 100644
--- a/vmime/messageId.hpp
+++ b/vmime/messageId.hpp
@@ -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;
-
-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;
/** 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);
};
diff --git a/vmime/messageIdSequence.hpp b/vmime/messageIdSequence.hpp
index 5dfb840a..6736d0a9 100644
--- a/vmime/messageIdSequence.hpp
+++ b/vmime/messageIdSequence.hpp
@@ -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;
};
diff --git a/vmime/parameter.hpp b/vmime/parameter.hpp
index e1b13a12..0773ea6b 100644
--- a/vmime/parameter.hpp
+++ b/vmime/parameter.hpp
@@ -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;
};
diff --git a/vmime/parameterizedHeaderField.hpp b/vmime/parameterizedHeaderField.hpp
index 2940ca3f..d2c934f7 100644
--- a/vmime/parameterizedHeaderField.hpp
+++ b/vmime/parameterizedHeaderField.hpp
@@ -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:
-
- using headerField::parse;
- using headerField::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:
- const std::vector <ref <const component> > getChildComponents() 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;
};
diff --git a/vmime/parserHelpers.hpp b/vmime/parserHelpers.hpp
index 9b075f73..d4f12465 100644
--- a/vmime/parserHelpers.hpp
+++ b/vmime/parserHelpers.hpp
@@ -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)
{
diff --git a/vmime/path.hpp b/vmime/path.hpp
index beaa72b7..eec8dfcb 100644
--- a/vmime/path.hpp
+++ b/vmime/path.hpp
@@ -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;
};
diff --git a/vmime/platforms/posix/posixFile.hpp b/vmime/platforms/posix/posixFile.hpp
index 70986dff..704b7b00 100644
--- a/vmime/platforms/posix/posixFile.hpp
+++ b/vmime/platforms/posix/posixFile.hpp
@@ -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;
diff --git a/vmime/platforms/windows/windowsFile.hpp b/vmime/platforms/windows/windowsFile.hpp
index 6e1c8fbb..f4170329 100644
--- a/vmime/platforms/windows/windowsFile.hpp
+++ b/vmime/platforms/windows/windowsFile.hpp
@@ -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:
diff --git a/vmime/relay.hpp b/vmime/relay.hpp
index 583ad804..dbaedf2c 100644
--- a/vmime/relay.hpp
+++ b/vmime/relay.hpp
@@ -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;
};
diff --git a/vmime/text.hpp b/vmime/text.hpp
index 15e11ae6..778ce865 100644
--- a/vmime/text.hpp
+++ b/vmime/text.hpp
@@ -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:
diff --git a/vmime/utility/inputStreamAdapter.hpp b/vmime/utility/inputStreamAdapter.hpp
index 278ab529..bd4d21e8 100644
--- a/vmime/utility/inputStreamAdapter.hpp
+++ b/vmime/utility/inputStreamAdapter.hpp
@@ -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:
diff --git a/vmime/utility/inputStreamByteBufferAdapter.hpp b/vmime/utility/inputStreamByteBufferAdapter.hpp
index 0f6a442d..b3dafd92 100644
--- a/vmime/utility/inputStreamByteBufferAdapter.hpp
+++ b/vmime/utility/inputStreamByteBufferAdapter.hpp
@@ -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:
diff --git a/vmime/utility/inputStreamStringAdapter.hpp b/vmime/utility/inputStreamStringAdapter.hpp
index a7d986f1..18a9083c 100644
--- a/vmime/utility/inputStreamStringAdapter.hpp
+++ b/vmime/utility/inputStreamStringAdapter.hpp
@@ -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:
diff --git a/vmime/utility/inputStreamStringProxyAdapter.hpp b/vmime/utility/inputStreamStringProxyAdapter.hpp
index 74b3f604..dc52637f 100644
--- a/vmime/utility/inputStreamStringProxyAdapter.hpp
+++ b/vmime/utility/inputStreamStringProxyAdapter.hpp
@@ -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:
diff --git a/vmime/utility/parserInputStreamAdapter.hpp b/vmime/utility/parserInputStreamAdapter.hpp
new file mode 100644
index 00000000..c24fa449
--- /dev/null
+++ b/vmime/utility/parserInputStreamAdapter.hpp
@@ -0,0 +1,173 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2012 Vincent Richard <[email protected]>
+//
+// 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
+
diff --git a/vmime/utility/seekableInputStream.hpp b/vmime/utility/seekableInputStream.hpp
new file mode 100644
index 00000000..c2ab1bb0
--- /dev/null
+++ b/vmime/utility/seekableInputStream.hpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2012 Vincent Richard <[email protected]>
+//
+// 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
+
diff --git a/vmime/utility/seekableInputStreamRegionAdapter.hpp b/vmime/utility/seekableInputStreamRegionAdapter.hpp
new file mode 100644
index 00000000..5ebccc62
--- /dev/null
+++ b/vmime/utility/seekableInputStreamRegionAdapter.hpp
@@ -0,0 +1,71 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2012 Vincent Richard <[email protected]>
+//
+// 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
+
diff --git a/vmime/utility/stream.hpp b/vmime/utility/stream.hpp
index 566ab9df..78be8277 100644
--- a/vmime/utility/stream.hpp
+++ b/vmime/utility/stream.hpp
@@ -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.
*
diff --git a/vmime/utility/streamUtils.hpp b/vmime/utility/streamUtils.hpp
index cdf70aad..87c8fc58 100644
--- a/vmime/utility/streamUtils.hpp
+++ b/vmime/utility/streamUtils.hpp
@@ -45,6 +45,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.
*
* @param is input stream (source data)
diff --git a/vmime/word.hpp b/vmime/word.hpp
index ad848eca..492aab5e 100644
--- a/vmime/word.hpp
+++ b/vmime/word.hpp
@@ -128,21 +128,52 @@ public:
#endif
- 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 generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos, const int flags, generatorState* state) 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;
- const std::vector <ref <const component> > getChildComponents() const;
+public:
-private:
+ using component::generate;
- 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);
+#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
+
+ const std::vector <ref <component> > getChildComponents();
+
+private:
- 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 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);
// The "m_buffer" of this word holds the data, and this data is encoded