00001
00002
00003
00004
00005
00006
00007
00008 #include "libtorrent/file.hpp"
00009 #include "libtorrent/utf8.hpp"
00010
00011 #ifdef UNICODE
00012 #include "libtorrent/storage.hpp"
00013 #endif
00014
00015 #include <sstream>
00016 #include <windows.h>
00017
00018 namespace
00019 {
00020
00021 class auto_localfree
00022 {
00023 public:
00024 auto_localfree(HLOCAL memory)
00025 : m_memory(memory)
00026 {
00027 }
00028 ~auto_localfree()
00029 {
00030 if (m_memory)
00031 LocalFree(m_memory);
00032 }
00033 private:
00034 HLOCAL m_memory;
00035 };
00036
00037 std::string utf8_native(std::string const& s)
00038 {
00039 try
00040 {
00041 std::wstring ws;
00042 libtorrent::utf8_wchar(s, ws);
00043 std::size_t size = wcstombs(0, ws.c_str(), 0);
00044 if (size == std::size_t(-1)) return s;
00045 std::string ret;
00046 ret.resize(size);
00047 size = wcstombs(&ret[0], ws.c_str(), size + 1);
00048 if (size == wchar_t(-1)) return s;
00049 ret.resize(size);
00050 return ret;
00051 }
00052 catch(std::exception)
00053 {
00054 return s;
00055 }
00056 }
00057
00058 void throw_exception(const char* thrower)
00059 {
00060 DWORD err = GetLastError();
00061
00062 #ifdef UNICODE
00063 wchar_t *wbuffer = 0;
00064 FormatMessage(
00065 FORMAT_MESSAGE_FROM_SYSTEM
00066 |FORMAT_MESSAGE_ALLOCATE_BUFFER
00067 , 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
00068 auto_localfree auto_free(wbuffer);
00069 std::string tmp_utf8;
00070 libtorrent::wchar_utf8(wbuffer, tmp_utf8);
00071 char const* buffer = tmp_utf8.c_str();
00072 #else
00073 char* buffer = 0;
00074 FormatMessage(
00075 FORMAT_MESSAGE_FROM_SYSTEM
00076 |FORMAT_MESSAGE_ALLOCATE_BUFFER
00077 , 0, err, 0, (LPSTR)&buffer, 0, 0);
00078 auto_localfree auto_free(buffer);
00079 #endif
00080
00081 std::stringstream s;
00082 s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");
00083
00084 throw libtorrent::file_error(s.str());
00085 }
00086 }
00087
00088 namespace libtorrent
00089 {
00090
00091 struct file::impl : boost::noncopyable
00092 {
00093 enum open_flags
00094 {
00095 read_flag = 1,
00096 write_flag = 2
00097 };
00098
00099 enum seek_mode
00100 {
00101 seek_begin = FILE_BEGIN,
00102 seek_from_here = FILE_CURRENT,
00103 seek_end = FILE_END
00104 };
00105
00106 impl()
00107 {
00108 m_file_handle = INVALID_HANDLE_VALUE;
00109 }
00110
00111 void open(const char *file_name, open_flags flags)
00112 {
00113 assert(file_name);
00114 assert(flags & (read_flag | write_flag));
00115
00116 DWORD access_mask = 0;
00117 if (flags & read_flag)
00118 access_mask |= GENERIC_READ;
00119 if (flags & write_flag)
00120 access_mask |= GENERIC_WRITE;
00121
00122 assert(access_mask & (GENERIC_READ | GENERIC_WRITE));
00123
00124 #ifdef UNICODE
00125 std::wstring wfile_name(safe_convert(file_name));
00126 HANDLE new_handle = CreateFile(
00127 wfile_name.c_str()
00128 , access_mask
00129 , FILE_SHARE_READ
00130 , 0
00131 , (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
00132 , FILE_ATTRIBUTE_NORMAL
00133 , 0);
00134 #else
00135 HANDLE new_handle = CreateFile(
00136 utf8_native(file_name).c_str()
00137 , access_mask
00138 , FILE_SHARE_READ
00139 , 0
00140 , (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
00141 , FILE_ATTRIBUTE_NORMAL
00142 , 0);
00143 #endif
00144
00145 if (new_handle == INVALID_HANDLE_VALUE)
00146 {
00147 std::stringstream s;
00148 throw_exception(file_name);
00149 }
00150
00151 close();
00152 m_file_handle = new_handle;
00153 }
00154
00155 void close()
00156 {
00157 if (m_file_handle != INVALID_HANDLE_VALUE)
00158 {
00159 CloseHandle(m_file_handle);
00160 m_file_handle = INVALID_HANDLE_VALUE;
00161 }
00162 }
00163
00164 ~impl()
00165 {
00166 close();
00167 }
00168
00169 size_type write(const char* buffer, size_type num_bytes)
00170 {
00171 assert(buffer);
00172 assert((DWORD)num_bytes == num_bytes);
00173 DWORD bytes_written = 0;
00174 if (num_bytes != 0)
00175 {
00176 if (FALSE == WriteFile(
00177 m_file_handle
00178 , buffer
00179 , (DWORD)num_bytes
00180 , &bytes_written
00181 , 0))
00182 {
00183 throw_exception("file::write");
00184 }
00185 }
00186 return bytes_written;
00187 }
00188
00189 size_type read(char* buffer, size_type num_bytes)
00190 {
00191 assert(buffer);
00192 assert(num_bytes >= 0);
00193 assert((DWORD)num_bytes == num_bytes);
00194
00195 DWORD bytes_read = 0;
00196 if (num_bytes != 0)
00197 {
00198 if (FALSE == ReadFile(
00199 m_file_handle
00200 , buffer
00201 , (DWORD)num_bytes
00202 , &bytes_read
00203 , 0))
00204 {
00205 throw_exception("file::read");
00206 }
00207 }
00208 return bytes_read;
00209 }
00210
00211 size_type seek(size_type pos, seek_mode from_where)
00212 {
00213 assert(pos >= 0 || from_where != seek_begin);
00214 assert(pos <= 0 || from_where != seek_end);
00215 LARGE_INTEGER offs;
00216 offs.QuadPart = pos;
00217 if (FALSE == SetFilePointerEx(
00218 m_file_handle
00219 , offs
00220 , &offs
00221 , from_where))
00222 {
00223 throw_exception("file::seek");
00224 }
00225 return offs.QuadPart;
00226 }
00227
00228 size_type tell()
00229 {
00230 LARGE_INTEGER offs;
00231 offs.QuadPart = 0;
00232
00233
00234 if (FALSE == SetFilePointerEx(
00235 m_file_handle
00236 , offs
00237 , &offs
00238 , FILE_CURRENT))
00239 {
00240 throw_exception("file::tell");
00241 }
00242
00243 size_type pos = offs.QuadPart;
00244 assert(pos >= 0);
00245 return pos;
00246 }
00247
00248 private:
00249
00250 HANDLE m_file_handle;
00251
00252 };
00253 }
00254
00255 namespace libtorrent
00256 {
00257
00258 const file::seek_mode file::begin(file::impl::seek_begin);
00259 const file::seek_mode file::end(file::impl::seek_end);
00260
00261 const file::open_mode file::in(file::impl::read_flag);
00262 const file::open_mode file::out(file::impl::write_flag);
00263
00264 file::file()
00265 : m_impl(new libtorrent::file::impl())
00266 {
00267 }
00268 file::file(boost::filesystem::path const& p, open_mode m)
00269 : m_impl(new libtorrent::file::impl())
00270 {
00271 open(p,m);
00272 }
00273
00274 file::~file()
00275 {
00276 }
00277
00278 void file::open(boost::filesystem::path const& p, open_mode m)
00279 {
00280 assert(p.is_complete());
00281 m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
00282 }
00283
00284 void file::close()
00285 {
00286 m_impl->close();
00287 }
00288
00289 size_type file::write(const char* buffer, size_type num_bytes)
00290 {
00291 return m_impl->write(buffer, num_bytes);
00292 }
00293
00294 size_type file::read(char* buffer, size_type num_bytes)
00295 {
00296 return m_impl->read(buffer, num_bytes);
00297 }
00298
00299 size_type file::seek(size_type pos, seek_mode m)
00300 {
00301 return m_impl->seek(pos,impl::seek_mode(m.m_val));
00302 }
00303
00304 size_type file::tell()
00305 {
00306 return m_impl->tell();
00307 }
00308 }