From 1c4429138317cbe3350159488aabe04b6b09883b Mon Sep 17 00:00:00 2001
From: Vincent Richard <vincent@vincent-richard.net>
Date: Tue, 25 Jun 2013 18:14:39 +0200
Subject: [PATCH] New content handler for file. Automatically set file size
 with file attachment.

---
 SConstruct                   |  1 +
 src/fileAttachment.cpp       | 40 ++++++++--------
 src/fileContentHandler.cpp   | 81 +++++++++++++++++++++++++++++++
 vmime/fileAttachment.hpp     | 16 ++++---
 vmime/fileContentHandler.hpp | 93 ++++++++++++++++++++++++++++++++++++
 5 files changed, 204 insertions(+), 27 deletions(-)
 create mode 100644 src/fileContentHandler.cpp
 create mode 100644 vmime/fileContentHandler.hpp

diff --git a/SConstruct b/SConstruct
index 9d048942..f390174d 100644
--- a/SConstruct
+++ b/SConstruct
@@ -75,6 +75,7 @@ libvmime_sources = [
 	'encoding.cpp', 'encoding.hpp',
 	'exception.cpp', 'exception.hpp',
 	'fileAttachment.cpp', 'fileAttachment.hpp',
+	'fileContentHandler.cpp', 'fileContentHandler.hpp',
 	'generatedMessageAttachment.hpp', 'generatedMessageAttachment.cpp',
 	'generationContext.hpp', 'generationContext.cpp',
 	'header.cpp', 'header.hpp',
diff --git a/src/fileAttachment.cpp b/src/fileAttachment.cpp
index ff6bee8a..4f4a87d3 100644
--- a/src/fileAttachment.cpp
+++ b/src/fileAttachment.cpp
@@ -79,20 +79,20 @@ fileAttachment::fileAttachment(const string& filepath, const mediaType& type,
 }
 
 
-fileAttachment::fileAttachment(ref <utility::inputStream> is, const word& filename, const mediaType& type)
+fileAttachment::fileAttachment(ref <contentHandler> cts, const word& filename, const mediaType& type)
 {
 	if (!filename.isEmpty())
 		m_fileInfo.setFilename(filename);
 
 	m_type = type;
 
-	setData(is);
+	setData(cts);
 
 	m_encoding = encoding::decide(m_data);
 }
 
 
-fileAttachment::fileAttachment(ref <utility::inputStream> is, const word& filename,
+fileAttachment::fileAttachment(ref <contentHandler> cts, const word& filename,
 	const mediaType& type, const text& desc)
 {
 	if (!filename.isEmpty())
@@ -101,13 +101,13 @@ fileAttachment::fileAttachment(ref <utility::inputStream> is, const word& filena
 	m_type = type;
 	m_desc = desc;
 
-	setData(is);
+	setData(cts);
 
 	m_encoding = encoding::decide(m_data);
 }
 
 
-fileAttachment::fileAttachment(ref <utility::inputStream> is, const word& filename,
+fileAttachment::fileAttachment(ref <contentHandler> cts, const word& filename,
 	const mediaType& type, const text& desc, const encoding& enc)
 {
 	if (!filename.isEmpty())
@@ -117,33 +117,33 @@ fileAttachment::fileAttachment(ref <utility::inputStream> is, const word& filena
 	m_desc = desc;
 	m_encoding = enc;
 
-	setData(is);
+	setData(cts);
 }
 
 
 void fileAttachment::setData(const string& filepath)
 {
-	std::ifstream* file = new std::ifstream();
-	file->open(filepath.c_str(), std::ios::in | std::ios::binary);
+	ref <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+	utility::file::path path = fsf->stringToPath(filepath);
 
-	if (!*file)
-	{
-		delete file;
+	ref <utility::file> file = fsf->create(path);
+
+	if (!file->isFile())
 		throw exceptions::open_file_error();
-	}
 
-	ref <utility::inputStream> is = vmime::create <utility::inputStreamPointerAdapter>(file, true);
+	m_data = vmime::create <streamContentHandler>
+		(file->getFileReader()->getInputStream(), file->getLength());
 
-	setData(is);
-
-	utility::file::path path = platform::getHandler()->getFileSystemFactory()->stringToPath(filepath);
 	m_fileInfo.setFilename(path.getLastComponent());
+	m_fileInfo.setSize(file->getLength());
 }
 
 
-void fileAttachment::setData(ref <utility::inputStream> is)
+void fileAttachment::setData(ref <contentHandler> cts)
 {
-	m_data = vmime::create <streamContentHandler>(is, 0);
+	m_data = cts;
+
+	m_fileInfo.setSize(cts->getLength());
 }
 
 
@@ -212,8 +212,8 @@ const datetime& fileAttachment::fileInfo::getReadDate() const { return (*m_readD
 void fileAttachment::fileInfo::setReadDate(const datetime& date) { if (m_readDate) { *m_readDate = date; } else { m_readDate = new datetime(date); } }
 
 bool fileAttachment::fileInfo::hasSize() const { return (m_size != NULL); }
-unsigned int fileAttachment::fileInfo::getSize() const { return (*m_size); }
-void fileAttachment::fileInfo::setSize(const unsigned int& size) { if (m_size) { *m_size = size; } else { m_size = new unsigned int(size); } }
+utility::stream::size_type fileAttachment::fileInfo::getSize() const { return (*m_size); }
+void fileAttachment::fileInfo::setSize(const utility::stream::size_type size) { if (m_size) { *m_size = size; } else { m_size = new utility::stream::size_type(size); } }
 
 
 } // vmime
diff --git a/src/fileContentHandler.cpp b/src/fileContentHandler.cpp
new file mode 100644
index 00000000..295bc887
--- /dev/null
+++ b/src/fileContentHandler.cpp
@@ -0,0 +1,81 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
+//
+// 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/fileContentHandler.hpp"
+
+
+namespace vmime
+{
+
+
+fileContentHandler::fileContentHandler()
+	: streamContentHandler()
+{
+}
+
+
+fileContentHandler::fileContentHandler
+	(ref <utility::file> file, const vmime::encoding& enc)
+{
+	setData(file, enc);
+}
+
+
+fileContentHandler::~fileContentHandler()
+{
+}
+
+
+fileContentHandler::fileContentHandler(const fileContentHandler& cts)
+	: streamContentHandler()
+{
+	setData(cts.m_file, cts.m_encoding);
+}
+
+
+fileContentHandler& fileContentHandler::operator=(const fileContentHandler& cts)
+{
+	setData(cts.m_file, cts.m_encoding);
+
+	return *this;
+}
+
+
+ref <contentHandler> fileContentHandler::clone() const
+{
+	return vmime::create <fileContentHandler>(*this);
+}
+
+
+void fileContentHandler::setData
+	(ref <utility::file> file, const vmime::encoding& enc)
+{
+	m_file = file;
+	m_encoding = enc;
+
+	streamContentHandler::setData
+		(file->getFileReader()->getInputStream(), file->getLength(), enc);
+}
+
+
+} // vmime
diff --git a/vmime/fileAttachment.hpp b/vmime/fileAttachment.hpp
index da4f638b..d18b8a14 100644
--- a/vmime/fileAttachment.hpp
+++ b/vmime/fileAttachment.hpp
@@ -33,6 +33,8 @@
 
 #include "vmime/defaultAttachment.hpp"
 #include "vmime/dateTime.hpp"
+#include "vmime/contentHandler.hpp"
+#include "vmime/utility/stream.hpp"
 
 
 namespace vmime
@@ -50,9 +52,9 @@ public:
 	fileAttachment(const string& filepath, const mediaType& type, const text& desc);
 	fileAttachment(const string& filepath, const mediaType& type, const text& desc, const encoding& enc);
 
-	fileAttachment(ref <utility::inputStream> is, const word& filename, const mediaType& type);
-	fileAttachment(ref <utility::inputStream> is, const word& filename, const mediaType& type, const text& desc);
-	fileAttachment(ref <utility::inputStream> is, const word& filename, const mediaType& type, const text& desc, const encoding& enc);
+	fileAttachment(ref <contentHandler> cts, const word& filename, const mediaType& type);
+	fileAttachment(ref <contentHandler> cts, const word& filename, const mediaType& type, const text& desc);
+	fileAttachment(ref <contentHandler> cts, const word& filename, const mediaType& type, const text& desc, const encoding& enc);
 
 	/** Stores information about a file attachment.
 	  */
@@ -156,18 +158,18 @@ public:
 		  *
 		  * @return file size
 		  */
-		unsigned int getSize() const;
+		utility::stream::size_type getSize() const;
 
 		/** Set the value of the 'size' property.
 		  *
 		  * @param size file size
 		  */
-		void setSize(const unsigned int& size);
+		void setSize(const utility::stream::size_type size);
 
 	private:
 
 		word* m_filename;
-		unsigned int* m_size;
+		utility::stream::size_type* m_size;
 		datetime* m_creationDate;
 		datetime* m_modifDate;
 		datetime* m_readDate;
@@ -179,7 +181,7 @@ public:
 private:
 
 	void setData(const string& filepath);
-	void setData(ref <utility::inputStream> is);
+	void setData(ref <contentHandler> cts);
 
 	fileInfo m_fileInfo;
 
diff --git a/vmime/fileContentHandler.hpp b/vmime/fileContentHandler.hpp
new file mode 100644
index 00000000..36a6a459
--- /dev/null
+++ b/vmime/fileContentHandler.hpp
@@ -0,0 +1,93 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
+//
+// 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_FILECONTENTHANDLER_HPP_INCLUDED
+#define VMIME_FILECONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/streamContentHandler.hpp"
+#include "vmime/utility/file.hpp"
+
+
+namespace vmime
+{
+
+
+/** A content handler which obtains its data from a file.
+  */
+
+class VMIME_EXPORT fileContentHandler : public streamContentHandler
+{
+public:
+
+	/** Creates a new empty content handler. No data can be extracted until
+	  * a file is attached using setData() function.
+	  *
+	  * @return a reference to a new content handler
+	  */
+	fileContentHandler();
+
+	/** Creates a new content handler using a file.
+	  *
+	  * @param file file from which data will be obtained
+	  * @param enc set to anything other than NO_ENCODING if the data contained
+	  * in the file is already encoded with the specified encoding
+	  *
+	  * @return a reference to a new content handler
+	  */
+	fileContentHandler
+		(ref <utility::file> file,
+		 const vmime::encoding& enc = NO_ENCODING);
+
+	~fileContentHandler();
+
+	fileContentHandler(const fileContentHandler& cts);
+	fileContentHandler& operator=(const fileContentHandler& cts);
+
+	ref <contentHandler> clone() const;
+
+	/** Sets the data managed by this content handler.
+	  *
+	  * @param file file from which data will be obtained
+	  * @param enc set to anything other than NO_ENCODING if the data contained
+	  * in the file is already encoded with the specified encoding
+	  */
+	void setData
+		(ref <utility::file> file,
+		 const vmime::encoding& enc = NO_ENCODING);
+
+private:
+
+	// Equals to NO_ENCODING if data is not encoded, otherwise this
+	// specifies the encoding that have been used to encode the data.
+	vmime::encoding m_encoding;
+
+	// Actual data
+	ref <utility::file> m_file;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_FILECONTENTHANDLER_HPP_INCLUDED