blob: 0b3ebe84031492f3e4b1a6c8ab19a26ae38545cf [file] [log] [blame]
#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