| #include "src/impl.h" |
| #include "libplatform/impl.h" /* for platform_win32_impl.h which declares Utf8ToFilename */ |
| #include <windows.h> |
| |
| namespace mp4v2 { |
| using namespace impl; |
| } |
| |
| /** |
| * Set this to 1 to compile in extra debugging |
| */ |
| #define EXTRA_DEBUG 0 |
| |
| /** |
| * @def LOG_PRINTF |
| * |
| * call log.printf if EXTRA_DEBUG is defined to 1. Do |
| * nothing otherwise |
| */ |
| #if EXTRA_DEBUG |
| #define LOG_PRINTF(X) log.printf X |
| #else |
| #define LOG_PRINTF(X) |
| #endif |
| |
| namespace mp4v2 { namespace platform { namespace io { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| class StandardFileProvider : public FileProvider |
| { |
| public: |
| StandardFileProvider(); |
| |
| bool open( std::string name, Mode mode ); |
| bool seek( Size pos ); |
| bool read( void* buffer, Size size, Size& nin, Size maxChunkSize ); |
| bool write( const void* buffer, Size size, Size& nout, Size maxChunkSize ); |
| bool close(); |
| bool getSize( Size& nout ); |
| |
| private: |
| HANDLE _handle; |
| |
| /** |
| * The UTF-8 encoded file name |
| */ |
| std::string _name; |
| |
| /** |
| * Argument for FileSystem::getFileSize() |
| */ |
| std::string _orig_name; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| StandardFileProvider::StandardFileProvider() |
| : _handle( INVALID_HANDLE_VALUE ) |
| { |
| } |
| |
| /** |
| * Open a file |
| * |
| * @param name the name of a file to open |
| * @param mode the mode to open @p name |
| * |
| * @retval false successfully opened @p name |
| * @retval true error opening @p name |
| */ |
| bool |
| StandardFileProvider::open( std::string name, Mode mode ) |
| { |
| _orig_name = name; |
| |
| DWORD access = 0; |
| DWORD share = 0; |
| DWORD crdisp = 0; |
| DWORD flags = FILE_ATTRIBUTE_NORMAL; |
| |
| switch( mode ) { |
| case MODE_UNDEFINED: |
| case MODE_READ: |
| default: |
| access |= GENERIC_READ; |
| share |= FILE_SHARE_READ; |
| crdisp |= OPEN_EXISTING; |
| break; |
| |
| case MODE_MODIFY: |
| access |= GENERIC_READ | GENERIC_WRITE; |
| share |= FILE_SHARE_READ; |
| crdisp |= OPEN_EXISTING; |
| break; |
| |
| case MODE_CREATE: |
| access |= GENERIC_READ | GENERIC_WRITE; |
| share |= FILE_SHARE_READ; |
| crdisp |= CREATE_ALWAYS; |
| break; |
| } |
| |
| win32::Utf8ToFilename filename(name); |
| |
| if (!filename.IsUTF16Valid()) |
| { |
| // The logging is done |
| return true; |
| } |
| |
| ASSERT(LPCWSTR(filename)); |
| _handle = CreateFileW( filename, access, share, NULL, crdisp, flags, NULL ); |
| if (_handle == INVALID_HANDLE_VALUE) |
| { |
| log.errorf("%s: CreateFileW(%s) failed (%d)",__FUNCTION__,filename.utf8.c_str(),GetLastError()); |
| return true; |
| } |
| |
| /* |
| ** Make a copy of the name for future log messages, etc. |
| */ |
| log.verbose2f("%s: CreateFileW(%s) succeeded",__FUNCTION__,filename.utf8.c_str()); |
| |
| _name = filename.utf8; |
| return false; |
| } |
| |
| /** |
| * Seek to an offset in the file |
| * |
| * @param pos the offset from the beginning of the file to |
| * seek to |
| * |
| * @retval false successfully seeked to @p pos |
| * @retval true error seeking to @p pos |
| */ |
| bool |
| StandardFileProvider::seek( Size pos ) |
| { |
| LARGE_INTEGER n; |
| |
| ASSERT(_handle != INVALID_HANDLE_VALUE); |
| |
| n.QuadPart = pos; |
| if (!SetFilePointerEx( _handle, n, NULL, FILE_BEGIN )) |
| { |
| log.errorf("%s: SetFilePointerEx(%s,%" PRId64 ") failed (%d)",__FUNCTION__,_name.c_str(), |
| pos,GetLastError()); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Read from the file |
| * |
| * @param buffer populated with at most @p size bytes from |
| * the file |
| * |
| * @param size the maximum number of bytes to read |
| * |
| * @param nin the |
| * |
| * @retval false successfully read from the file |
| * @retval true error reading from the file |
| */ |
| bool |
| StandardFileProvider::read( void* buffer, Size size, Size& nin, Size maxChunkSize ) |
| { |
| DWORD nread = 0; |
| |
| ASSERT(_handle != INVALID_HANDLE_VALUE); |
| |
| // ReadFile takes a DWORD for number of bytes to read so |
| // make sure we're not asking for more than fits. |
| // MAXDWORD from WinNT.h. |
| ASSERT(size <= MAXDWORD); |
| if( ReadFile( _handle, buffer, (DWORD)(size & MAXDWORD), &nread, NULL ) == 0 ) |
| { |
| log.errorf("%s: ReadFile(%s,%d) failed (%d)",__FUNCTION__,_name.c_str(), |
| (DWORD)(size & MAXDWORD),GetLastError()); |
| return true; |
| } |
| LOG_PRINTF((MP4_LOG_VERBOSE3,"%s: ReadFile(%s,%d) succeeded: read %d byte(s)",__FUNCTION__, |
| _name.c_str(),(DWORD)(size & MAXDWORD),nread)); |
| nin = nread; |
| return false; |
| } |
| |
| /** |
| * Write to the file |
| * |
| * @param buffer the data to write |
| * |
| * @param size the number of bytes of @p buffer to write |
| * |
| * @param nout populated with the number of bytes actually |
| * written if the function succeeds |
| * |
| * @retval false successfully wrote to the file |
| * @retval true error writing to the file |
| */ |
| bool |
| StandardFileProvider::write( const void* buffer, Size size, Size& nout, Size maxChunkSize ) |
| { |
| DWORD nwrote = 0; |
| |
| ASSERT(_handle != INVALID_HANDLE_VALUE); |
| |
| // ReadFile takes a DWORD for number of bytes to read so |
| // make sure we're not asking for more than fits. |
| // MAXDWORD from WinNT.h. |
| ASSERT(size <= MAXDWORD); |
| if( WriteFile( _handle, buffer, (DWORD)(size & MAXDWORD), &nwrote, NULL ) == 0 ) |
| { |
| log.errorf("%s: WriteFile(%s,%d) failed (%d)",__FUNCTION__,_name.c_str(), |
| (DWORD)(size & MAXDWORD),GetLastError()); |
| return true; |
| } |
| log.verbose2f("%s: WriteFile(%s,%d) succeeded: wrote %d byte(s)",__FUNCTION__, |
| _name.c_str(),(DWORD)(size & MAXDWORD),nwrote); |
| nout = nwrote; |
| return false; |
| } |
| |
| /** |
| * Close the file |
| * |
| * @retval false successfully closed the file |
| * @retval true error closing the file |
| */ |
| bool |
| StandardFileProvider::close() |
| { |
| BOOL retval; |
| |
| retval = CloseHandle( _handle ); |
| if (!retval) |
| { |
| log.errorf("%s: CloseHandle(%s) failed (%d)",__FUNCTION__, |
| _name.c_str(),GetLastError()); |
| } |
| |
| // Whether we succeeded or not, clear the handle and |
| // forget the name |
| _handle = INVALID_HANDLE_VALUE; |
| _name.clear(); |
| |
| // CloseHandle return 0/false to indicate failure, but |
| // we return 0/false to indicate success, so negate. |
| return !retval; |
| } |
| |
| /** |
| * Get the size of a the file in bytes |
| * |
| * @param nout populated with the size of the file in |
| * bytes if the function succeeds |
| * |
| * @retval false successfully got the file size |
| * @retval true error getting the file size |
| */ |
| bool |
| StandardFileProvider::getSize( Size& nout ) |
| { |
| BOOL retval; |
| |
| // getFileSize will log if it fails |
| // (cannot use _name because it may have UNC prefix) |
| retval = FileSystem::getFileSize( _orig_name, nout ); |
| |
| return retval; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| FileProvider& |
| FileProvider::standard() |
| { |
| return *new StandardFileProvider(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| }}} // namespace mp4v2::platform::io |