//
// VMime library (http://vmime.sourceforge.net)
// Copyright (C) 2002-2006 Vincent Richard <vincent@vincent-richard.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 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/platforms/windows/windowsFile.hpp"
#include <windows.h>
#include <string.h>
#include "vmime/exception.hpp"
#include "vmime/utility/stringUtils.hpp"
#if VMIME_HAVE_FILESYSTEM_FEATURES
namespace vmime {
namespace platforms {
namespace windows {
ref <vmime::utility::file> windowsFileSystemFactory::create(const vmime::utility::file::path& path) const
{
return vmime::create <windowsFile>(path);
}
const vmime::utility::file::path windowsFileSystemFactory::stringToPath(const vmime::string& str) const
{
return (stringToPathImpl(str));
}
const vmime::string windowsFileSystemFactory::pathToString(const vmime::utility::file::path& path) const
{
return (pathToStringImpl(path));
}
const vmime::utility::file::path windowsFileSystemFactory::stringToPathImpl(const vmime::string& str)
{
vmime::string::size_type offset = 0;
vmime::string::size_type prev = 0;
vmime::utility::file::path path;
while ((offset = str.find_first_of("\\", offset)) != vmime::string::npos)
{
if (offset != prev)
path.appendComponent(vmime::string(str.begin() + prev, str.begin() + offset));
prev = offset + 1;
offset++;
}
if (prev < str.length())
path.appendComponent(vmime::string(str.begin() + prev, str.end()));
return (path);
}
const vmime::string windowsFileSystemFactory::pathToStringImpl(const vmime::utility::file::path& path)
{
vmime::string native = "";
for (int i = 0 ; i < path.getSize() ; ++i)
{
if (i > 0)
native += "\\";
native += path[i].getBuffer();
}
return (native);
}
const bool windowsFileSystemFactory::isValidPathComponent(const vmime::utility::file::path::component& comp) const
{
return isValidPathComponent(comp, false);
}
const bool windowsFileSystemFactory::isValidPathComponent(
const vmime::utility::file::path::component& comp,
bool firstComponent) const
{
const string& buffer = comp.getBuffer();
// If first component, check if component is a drive
if (firstComponent && (buffer.length() == 2) && (buffer[1] == ':'))
{
char drive = tolower(buffer[0]);
if ((drive >= 'a') && (drive <= 'z'))
return true;
}
// Check for invalid characters
for (string::size_type i = 0 ; i < buffer.length() ; ++i)
{
const unsigned char c = buffer[i];
switch (c)
{
// Reserved characters
case '<': case '>': case ':':
case '"': case '/': case '\\':
case '|': case '$': case '*':
return false;
default:
if (c <= 31)
return false;
}
}
string upperBuffer = vmime::utility::stringUtils::toUpper(buffer);
// Check for reserved names
if (upperBuffer.length() == 3)
{
if (upperBuffer == "CON" || buffer == "PRN" || buffer == "AUX" || buffer == "NUL")
return false;
}
else if (upperBuffer.length() == 4)
{
if ((upperBuffer.substr(0, 3) == "COM") && // COM0 to COM9
(upperBuffer[3] >= '0') && (upperBuffer[3] <= '9'))
{
return false;
}
else if ((upperBuffer.substr(0, 3) == "LPT") && // LPT0 to LPT9
(upperBuffer[3] >= '0') && (upperBuffer[3] <= '9'))
{
return false;
}
}
return true;
}
const bool windowsFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const
{
for (int i = 0 ; i < path.getSize() ; ++i)
{
if (!isValidPathComponent(path[i], (i==0)))
return false;
}
return true;
}
void windowsFileSystemFactory::reportError(const vmime::utility::path& path, const int err)
{
vmime::string desc;
LPVOID lpMsgBuf;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL ))
{
desc = (char*)lpMsgBuf;
LocalFree( lpMsgBuf );
}
throw vmime::exceptions::filesystem_exception(desc, path);
}
windowsFile::windowsFile(const vmime::utility::file::path& path)
: m_path(path), m_nativePath(windowsFileSystemFactory::pathToStringImpl(path))
{
}
void windowsFile::createFile()
{
HANDLE hFile = CreateFile(
m_nativePath.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
windowsFileSystemFactory::reportError(m_path, GetLastError());
CloseHandle(hFile);
}
void windowsFile::createDirectory(const bool createAll)
{
createDirectoryImpl(m_path, m_path, createAll);
}
const bool windowsFile::isFile() const
{
DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str());
if (dwFileAttribute == INVALID_FILE_ATTRIBUTES)
return false;
return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == 0;
}
const bool windowsFile::isDirectory() const
{
DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str());
if (dwFileAttribute == INVALID_FILE_ATTRIBUTES)
return false;
return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
}
const bool windowsFile::canRead() const
{
HANDLE hFile = CreateFile(
m_nativePath.c_str(),
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return false;
CloseHandle(hFile);
return true;
}
const bool windowsFile::canWrite() const
{
HANDLE hFile = CreateFile(
m_nativePath.c_str(),
GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return false;
CloseHandle(hFile);
return true;
}
const windowsFile::length_type windowsFile::getLength()
{
HANDLE hFile = CreateFile(
m_nativePath.c_str(),
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
windowsFileSystemFactory::reportError(m_path, GetLastError());
DWORD dwSize = GetFileSize(hFile, NULL);
CloseHandle(hFile);
return dwSize;
}
const vmime::utility::path& windowsFile::getFullPath() const
{
return m_path;
}
const bool windowsFile::exists() const
{
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile(m_nativePath.c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
return true;
}
return false;
}
ref <vmime::utility::file> windowsFile::getParent() const
{
if (m_path.isEmpty())
return NULL;
else
return vmime::create <windowsFile>(m_path.getParent());
}
void windowsFile::rename(const path& newName)
{
const vmime::string newNativeName = windowsFileSystemFactory::pathToStringImpl(newName);
if (MoveFile(m_nativePath.c_str(), newNativeName.c_str()))
{
m_path = newName;
m_nativePath = newNativeName;
}
else
windowsFileSystemFactory::reportError(m_path, GetLastError());
}
void windowsFile::remove()
{
if (!DeleteFile(m_nativePath.c_str()))
windowsFileSystemFactory::reportError(m_path, GetLastError());
}
ref <vmime::utility::fileWriter> windowsFile::getFileWriter()
{
return vmime::create <windowsFileWriter>(m_path, m_nativePath);
}
ref <vmime::utility::fileReader> windowsFile::getFileReader()
{
return vmime::create <windowsFileReader>(m_path, m_nativePath);
}
ref <vmime::utility::fileIterator> windowsFile::getFiles() const
{
return vmime::create <windowsFileIterator>(m_path, m_nativePath);
}
void windowsFile::createDirectoryImpl(const vmime::utility::file::path& fullPath, const vmime::utility::file::path& path, const bool recursive)
{
const vmime::string nativePath = windowsFileSystemFactory::pathToStringImpl(path);
windowsFile tmp(fullPath);
if (tmp.isDirectory())
return;
if (!path.isEmpty() && recursive)
createDirectoryImpl(fullPath, path.getParent(), true);
if (!CreateDirectory(nativePath.c_str(), NULL))
windowsFileSystemFactory::reportError(fullPath, GetLastError());
}
windowsFileIterator::windowsFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath)
: m_path(path), m_nativePath(nativePath), m_moreElements(false), m_hFind(INVALID_HANDLE_VALUE)
{
findFirst();
}
windowsFileIterator::~windowsFileIterator()
{
if (m_hFind != INVALID_HANDLE_VALUE)
FindClose(m_hFind);
}
const bool windowsFileIterator::hasMoreElements() const
{
return m_moreElements;
}
ref <vmime::utility::file> windowsFileIterator::nextElement()
{
ref <vmime::utility::file> pFile = vmime::create <windowsFile>
(m_path / vmime::utility::file::path::component(m_findData.cFileName));
findNext();
return pFile;
}
void windowsFileIterator::findFirst()
{
m_hFind = FindFirstFile(m_nativePath.c_str(), &m_findData);
if (m_hFind == INVALID_HANDLE_VALUE)
{
m_moreElements = false;
return;
}
m_moreElements = true;
if (isCurrentOrParentDir())
findNext();
}
void windowsFileIterator::findNext()
{
do
{
if (!FindNextFile(m_hFind, &m_findData))
{
m_moreElements = false;
return;
}
}
while (isCurrentOrParentDir());
}
bool windowsFileIterator::isCurrentOrParentDir() const
{
vmime::string s(m_findData.cFileName);
if ((s == ".") || (s == ".."))
return true;
return false;
}
windowsFileReader::windowsFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath)
: m_path(path), m_nativePath(nativePath)
{
}
ref <vmime::utility::inputStream> windowsFileReader::getInputStream()
{
HANDLE hFile = CreateFile(
m_nativePath.c_str(),
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
windowsFileSystemFactory::reportError(m_path, GetLastError());
return vmime::create <windowsFileReaderInputStream>(m_path, hFile);
}
windowsFileReaderInputStream::windowsFileReaderInputStream(const vmime::utility::file::path& path, HANDLE hFile)
: m_path(path), m_hFile(hFile)
{
}
windowsFileReaderInputStream::~windowsFileReaderInputStream()
{
CloseHandle(m_hFile);
}
const bool windowsFileReaderInputStream::eof() const
{
DWORD dwSize = GetFileSize(m_hFile, NULL);
DWORD dwPosition = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
return (dwSize == dwPosition);
}
void windowsFileReaderInputStream::reset()
{
SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN);
}
const vmime::utility::stream::size_type windowsFileReaderInputStream::read(value_type* const data, const size_type count)
{
DWORD dwBytesRead;
if (!ReadFile(m_hFile, (LPVOID)data, (DWORD)count, &dwBytesRead, NULL))
windowsFileSystemFactory::reportError(m_path, GetLastError());
return dwBytesRead;
}
const vmime::utility::stream::size_type windowsFileReaderInputStream::skip(const size_type count)
{
DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
DWORD dwNewPos = SetFilePointer(m_hFile, (LONG)count, NULL, FILE_CURRENT);
return (dwNewPos - dwCurPos);
}
windowsFileWriter::windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath)
: m_path(path), m_nativePath(nativePath)
{
}
ref <vmime::utility::outputStream> windowsFileWriter::getOutputStream()
{
HANDLE hFile = CreateFile(
m_nativePath.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
windowsFileSystemFactory::reportError(m_path, GetLastError());
return vmime::create <windowsFileWriterOutputStream>(m_path, hFile);
}
windowsFileWriterOutputStream::windowsFileWriterOutputStream(const vmime::utility::file::path& path, HANDLE hFile)
: m_path(path), m_hFile(hFile)
{
}
windowsFileWriterOutputStream::~windowsFileWriterOutputStream()
{
CloseHandle(m_hFile);
}
void windowsFileWriterOutputStream::write(const value_type* const data, const size_type count)
{
DWORD dwBytesWritten;
if (!WriteFile(m_hFile, data, (DWORD)count, &dwBytesWritten, NULL))
windowsFileSystemFactory::reportError(m_path, GetLastError());
}
void windowsFileWriterOutputStream::flush()
{
// TODO
}
} // windows
} // platforms
} // vmime
#endif // VMIME_HAVE_FILESYSTEM_FEATURES
syntax highlighted by Code2HTML, v. 0.9.1