#define _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE64
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <string.h>
#if !defined(_WIN32_WCE)
#include <errno.h>
#include <sys/stat.h>
#endif
#if defined(_WIN32)
#include <io.h>
#include <fcntl.h>
#endif
#include "Ap4FileByteStream.h"
#if !defined(ENOENT)
#define ENOENT 2
#endif
#if !defined(EACCES)
#define EACCES 13
#endif
#if !defined(AP4_CONFIG_HAVE_FOPEN_S)
static int fopen_s(FILE** file,
const char* filename,
const char* mode)
{
*file = fopen(filename, mode);
#if defined(UNDER_CE)
if (*file == NULL) return ENOENT;
#else
if (*file == NULL) return errno;
#endif
return 0;
}
#endif
#if defined(_WIN32)
#include <windows.h>
#include <malloc.h>
#include <limits.h>
#include <assert.h>
#define AP4_WIN32_USE_CHAR_CONVERSION \
int _convert = 0; \
LPCWSTR _lpw = NULL; \
LPCSTR _lpa = NULL
static LPWSTR
A2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
{
int ret;
assert(lpa != NULL);
assert(lpw != NULL);
if (lpw == NULL || lpa == NULL) return NULL;
lpw[0] = '\0';
ret = MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
if (ret == 0) {
assert(0);
return NULL;
}
return lpw;
}
static LPSTR
W2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp)
{
int ret;
assert(lpw != NULL);
assert(lpa != NULL);
if (lpa == NULL || lpw == NULL) return NULL;
lpa[0] = '\0';
ret = WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
if (ret == 0) {
int error = GetLastError();
assert(error);
return NULL;
}
return lpa;
}
#define AP4_WIN32_A2W(lpa) \
(((_lpa = lpa) == NULL) ? \
NULL : \
(_convert = MultiByteToWideChar(CP_UTF8, 0, lpa, -1, NULL, 0), \
(INT_MAX / 2 < _convert) ? \
NULL : \
A2WHelper((LPWSTR)alloca(_convert * sizeof(WCHAR)), _lpa, _convert, CP_UTF8)))
#define AP4_WIN32_W2A(lpw) \
(((_lpw = lpw) == NULL) ? \
NULL : \
((_convert = WideCharToMultiByte(CP_UTF8, 0, lpw, -1, NULL, 0, NULL, NULL), \
(_convert > INT_MAX / 2) ? \
NULL : \
W2AHelper((LPSTR)alloca(_convert), _lpw, _convert, CP_UTF8))))
static errno_t
AP4_fopen_s_utf8(FILE** file, const char* path, const char* mode)
{
AP4_WIN32_USE_CHAR_CONVERSION;
return _wfopen_s(file, AP4_WIN32_A2W(path), AP4_WIN32_A2W(mode));
}
#define fopen_s AP4_fopen_s_utf8
#endif
class AP4_StdcFileByteStream: public AP4_ByteStream
{
public:
static AP4_Result Create(AP4_FileByteStream* delegator,
const char* name,
AP4_FileByteStream::Mode mode,
AP4_ByteStream*& stream);
AP4_StdcFileByteStream(AP4_FileByteStream* delegator,
FILE* file,
AP4_LargeSize size);
~AP4_StdcFileByteStream();
AP4_Result ReadPartial(void* buffer,
AP4_Size bytesToRead,
AP4_Size& bytesRead);
AP4_Result WritePartial(const void* buffer,
AP4_Size bytesToWrite,
AP4_Size& bytesWritten);
AP4_Result Seek(AP4_Position position);
AP4_Result Tell(AP4_Position& position);
AP4_Result GetSize(AP4_LargeSize& size);
AP4_Result Flush();
void AddReference();
void Release();
private:
AP4_ByteStream* m_Delegator;
AP4_Cardinal m_ReferenceCount;
FILE* m_File;
AP4_Position m_Position;
AP4_LargeSize m_Size;
};
AP4_Result
AP4_StdcFileByteStream::Create(AP4_FileByteStream* delegator,
const char* name,
AP4_FileByteStream::Mode mode,
AP4_ByteStream*& stream)
{
stream = NULL;
if (name == NULL) return AP4_ERROR_INVALID_PARAMETERS;
FILE* file = NULL;
AP4_Position size = 0;
if (!strcmp(name, "-stdin") || !strcmp(name, "-stdin#")) {
file = stdin;
#if defined(_WIN32)
if (name[6] == '#') {
_setmode(fileno(stdin), O_BINARY);
}
#endif
} else if (!strcmp(name, "-stdout") || !strcmp(name, "-stdout#")) {
file = stdout;
#if defined(_WIN32)
if (name[7] == '#') {
_setmode(fileno(stdout), O_BINARY);
}
#endif
} else if (!strcmp(name, "-stderr")) {
file = stderr;
} else {
int open_result;
switch (mode) {
case AP4_FileByteStream::STREAM_MODE_READ:
open_result = fopen_s(&file, name, "rb");
break;
case AP4_FileByteStream::STREAM_MODE_WRITE:
open_result = fopen_s(&file, name, "wb+");
break;
case AP4_FileByteStream::STREAM_MODE_READ_WRITE:
open_result = fopen_s(&file, name, "r+b");
break;
default:
return AP4_ERROR_INVALID_PARAMETERS;
}
if (open_result != 0) {
if (open_result == ENOENT) {
return AP4_ERROR_NO_SUCH_FILE;
} else if (open_result == EACCES) {
return AP4_ERROR_PERMISSION_DENIED;
} else {
return AP4_ERROR_CANNOT_OPEN_FILE;
}
}
if (AP4_fseek(file, 0, SEEK_END) >= 0) {
size = AP4_ftell(file);
AP4_fseek(file, 0, SEEK_SET);
}
}
stream = new AP4_StdcFileByteStream(delegator, file, size);
return AP4_SUCCESS;
}
AP4_StdcFileByteStream::AP4_StdcFileByteStream(AP4_FileByteStream* delegator,
FILE* file,
AP4_LargeSize size) :
m_Delegator(delegator),
m_ReferenceCount(1),
m_File(file),
m_Position(0),
m_Size(size)
{
}
AP4_StdcFileByteStream::~AP4_StdcFileByteStream()
{
if (m_File && m_File != stdin && m_File != stdout && m_File != stderr) {
fclose(m_File);
}
}
void
AP4_StdcFileByteStream::AddReference()
{
m_ReferenceCount++;
}
void
AP4_StdcFileByteStream::Release()
{
if (--m_ReferenceCount == 0) {
if (m_Delegator) {
delete m_Delegator;
} else {
delete this;
}
}
}
AP4_Result
AP4_StdcFileByteStream::ReadPartial(void* buffer,
AP4_Size bytesToRead,
AP4_Size& bytesRead)
{
size_t nbRead;
nbRead = fread(buffer, 1, bytesToRead, m_File);
if (nbRead > 0) {
bytesRead = (AP4_Size)nbRead;
m_Position += nbRead;
return AP4_SUCCESS;
} else if (feof(m_File)) {
bytesRead = 0;
return AP4_ERROR_EOS;
} else {
bytesRead = 0;
return AP4_ERROR_READ_FAILED;
}
}
AP4_Result
AP4_StdcFileByteStream::WritePartial(const void* buffer,
AP4_Size bytesToWrite,
AP4_Size& bytesWritten)
{
size_t nbWritten;
if (bytesToWrite == 0) return AP4_SUCCESS;
nbWritten = fwrite(buffer, 1, bytesToWrite, m_File);
if (nbWritten > 0) {
bytesWritten = (AP4_Size)nbWritten;
m_Position += nbWritten;
if (m_Position > m_Size) {
m_Size = m_Position;
}
return AP4_SUCCESS;
} else {
bytesWritten = 0;
return AP4_ERROR_WRITE_FAILED;
}
}
AP4_Result
AP4_StdcFileByteStream::Seek(AP4_Position position)
{
if (position == m_Position) return AP4_SUCCESS;
size_t result;
result = AP4_fseek(m_File, position, SEEK_SET);
if (result == 0) {
m_Position = position;
return AP4_SUCCESS;
} else {
return AP4_FAILURE;
}
}
AP4_Result
AP4_StdcFileByteStream::Tell(AP4_Position& position)
{
position = m_Position;
return AP4_SUCCESS;
}
AP4_Result
AP4_StdcFileByteStream::GetSize(AP4_LargeSize& size)
{
size = m_Size;
return AP4_SUCCESS;
}
AP4_Result
AP4_StdcFileByteStream::Flush()
{
int ret_val = fflush(m_File);
return (ret_val > 0) ? AP4_FAILURE: AP4_SUCCESS;
}
AP4_Result
AP4_FileByteStream::Create(const char* name,
AP4_FileByteStream::Mode mode,
AP4_ByteStream*& stream)
{
return AP4_StdcFileByteStream::Create(NULL, name, mode, stream);
}
#if !defined(AP4_CONFIG_NO_EXCEPTIONS)
AP4_FileByteStream::AP4_FileByteStream(const char* name,
AP4_FileByteStream::Mode mode)
{
AP4_ByteStream* stream = NULL;
AP4_Result result = AP4_StdcFileByteStream::Create(this, name, mode, stream);
if (AP4_FAILED(result)) throw AP4_Exception(result);
m_Delegate = stream;
}
#endif