diff options
| author | Vincent Richard <[email protected]> | 2012-04-16 20:32:33 +0000 |
|---|---|---|
| committer | Vincent Richard <[email protected]> | 2012-04-16 20:32:33 +0000 |
| commit | 4f33877820edee1b47d1b6f4fc800eaad273adaa (patch) | |
| tree | 10d5d339f17f2561ef46993de308c2e7d8a9fd79 /src | |
| parent | Split stream.hpp/.cpp into multiple source files. (diff) | |
| download | vmime-4f33877820edee1b47d1b6f4fc800eaad273adaa.tar.gz vmime-4f33877820edee1b47d1b6f4fc800eaad273adaa.zip | |
Added ability to parse directly from an input stream (eg. file). This allows very big messages to be parsed without loading the whole message data into memory.
Diffstat (limited to 'src')
35 files changed, 770 insertions, 188 deletions
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 != utility::stream::npos) && (pos + 3 < end)) + pos += 3; // skip \n-- + } - if ((pos != string::npos) && (pos < end)) + 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; + while (boundaryLen != 0 && + parserHelpers::isSpace(boundaryBytes[boundaryLen - 1])) + { + boundaryLen--; + } - boundary = string(buffer.begin() + start, - buffer.begin() + pos); + if (boundaryLen >= 1) + boundary = string(boundaryBytes, boundaryBytes + boundaryLen); } } } @@ -126,51 +170,79 @@ void body::parse(const string& buffer, const string::size_type position, { const string boundarySep("--" + boundary); - string::size_type partStart = position; - string::size_type pos = position; + utility::stream::size_type partStart = position; + utility::stream::size_type pos = position; bool lastPart = false; - while (pos != string::npos && pos < end) + while (pos != utility::stream::npos && pos < end) { - pos = buffer.find(boundarySep, pos); + pos = parser->findNext(boundarySep, pos); + + if (pos == utility::stream::npos) + break; // not found - if (pos == string::npos || - ((pos == 0 || buffer[pos - 1] == '\n') && - (buffer[pos + boundarySep.length()] == '\r' || - buffer[pos + boundarySep.length()] == '\n' || - buffer[pos + boundarySep.length()] == '-' - ) - ) - ) + if (pos != 0) { - break; + parser->seek(pos - 1); + + if (parser->peekByte() != '\n') + { + // Boundary is not at a beginning of a line + pos++; + continue; + } + + parser->skip(1 + boundarySep.length()); + } + else + { + parser->seek(pos + boundarySep.length()); } - // boundary not a beginning of line, or just a prefix of another, continue the search. + const utility::stream::value_type next = parser->peekByte(); + + if (next == '\r' || next == '\n' || next == '-') + break; + + // Boundary is a prefix of another, continue the search pos++; } - if (pos != string::npos && pos < end) + if (pos != utility::stream::npos && pos < end) { vmime::text text; - text.parse(buffer, position, pos); + text.parse(parser, position, pos); m_prologText = text.getWholeBuffer(); } - for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index) + for (int index = 0 ; !lastPart && (pos != utility::stream::npos) && (pos < end) ; ++index) { - string::size_type partEnd = pos; + utility::stream::size_type partEnd = pos; // Get rid of the [CR]LF just before the boundary string - if (pos >= (position + 1) && buffer[pos - 1] == '\n') --partEnd; - if (pos >= (position + 2) && buffer[pos - 2] == '\r') --partEnd; + if (pos >= (position + 1)) + { + parser->seek(pos - 1); + + if (parser->peekByte() == '\n') + --partEnd; + } + + if (pos >= (position + 2)) + { + parser->seek(pos - 2); + + if (parser->peekByte() == '\r') + --partEnd; + } // Check whether it is the last part (boundary terminated by "--") pos += boundarySep.length(); + parser->seek(pos); - if (pos + 1 < end && buffer[pos] == '-' && buffer[pos + 1] == '-') + if (pos + 1 < end && parser->matchBytes("--", 2)) { lastPart = true; pos += 2; @@ -180,15 +252,15 @@ void body::parse(const string& buffer, const string::size_type position, // "...(If a boundary appears to end with white space, the // white space must be presumed to have been added by a // gateway, and must be deleted.)..." - while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) - ++pos; + parser->seek(pos); + pos += parser->skipIf(parserHelpers::isSpaceOrTab, end); // End of boundary line - if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] =='\n') + if (pos + 1 < end && parser->matchBytes("\r\n", 2)) { pos += 2; } - else if (pos < end && buffer[pos] == '\n') + else if (pos < end && parser->peekByte() == '\n') { ++pos; } @@ -202,7 +274,7 @@ void body::parse(const string& buffer, const string::size_type position, if (partEnd < partStart) std::swap(partStart, partEnd); - part->parse(buffer, partStart, partEnd, NULL); + part->parse(parser, partStart, partEnd, NULL); part->m_parent = m_part; m_parts.push_back(part); @@ -210,23 +282,37 @@ void body::parse(const string& buffer, const string::size_type position, partStart = pos; - while (pos != string::npos && pos < end) + while (pos != utility::stream::npos && pos < end) { - pos = buffer.find(boundarySep, pos); + pos = parser->findNext(boundarySep, pos); + + if (pos == utility::stream::npos) + break; // not found - if (pos == string::npos || - ((pos == 0 || buffer[pos - 1] == '\n') && - (buffer[pos + boundarySep.length()] == '\r' || - buffer[pos + boundarySep.length()] == '\n' || - buffer[pos + boundarySep.length()] == '-' - ) - ) - ) + if (pos != 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> >(); } |
