You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
9.4 KiB
402 lines
9.4 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Utility Library
|
|
* ----------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief File abstraction.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "deFile.h"
|
|
#include "deMemory.h"
|
|
|
|
#if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_SYMBIAN) || (DE_OS == DE_OS_QNX)
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
struct deFile_s
|
|
{
|
|
int fd;
|
|
};
|
|
|
|
deBool deFileExists (const char* filename)
|
|
{
|
|
struct stat st;
|
|
int result = stat(filename, &st);
|
|
return result == 0;
|
|
}
|
|
|
|
deBool deDeleteFile (const char* filename)
|
|
{
|
|
return unlink(filename) == 0;
|
|
}
|
|
|
|
deFile* deFile_createFromHandle (deUintptr handle)
|
|
{
|
|
int fd = (int)handle;
|
|
deFile* file = (deFile*)deCalloc(sizeof(deFile));
|
|
if (!file)
|
|
{
|
|
close(fd);
|
|
return file;
|
|
}
|
|
|
|
file->fd = fd;
|
|
return file;
|
|
}
|
|
|
|
static int mapOpenMode (deFileMode mode)
|
|
{
|
|
int flag = 0;
|
|
|
|
/* Read, write or read and write access is required. */
|
|
DE_ASSERT((mode & DE_FILEMODE_READ) != 0 || ((mode & DE_FILEMODE_WRITE) != 0));
|
|
|
|
/* Create, open or create and open mode is required. */
|
|
DE_ASSERT((mode & DE_FILEMODE_OPEN) != 0 || ((mode & DE_FILEMODE_CREATE) != 0));
|
|
|
|
/* Require write when using create. */
|
|
DE_ASSERT(!(mode & DE_FILEMODE_CREATE) || (mode & DE_FILEMODE_WRITE));
|
|
|
|
/* Require write and open when using truncate */
|
|
DE_ASSERT(!(mode & DE_FILEMODE_TRUNCATE) || ((mode & DE_FILEMODE_WRITE) && (mode & DE_FILEMODE_OPEN)));
|
|
|
|
if (mode & DE_FILEMODE_READ)
|
|
flag |= O_RDONLY;
|
|
|
|
if (mode & DE_FILEMODE_WRITE)
|
|
flag |= O_WRONLY;
|
|
|
|
if (mode & DE_FILEMODE_TRUNCATE)
|
|
flag |= O_TRUNC;
|
|
|
|
if (mode & DE_FILEMODE_CREATE)
|
|
flag |= O_CREAT;
|
|
|
|
if (!(mode & DE_FILEMODE_OPEN))
|
|
flag |= O_EXCL;
|
|
|
|
return flag;
|
|
}
|
|
|
|
deFile* deFile_create (const char* filename, deUint32 mode)
|
|
{
|
|
int fd = open(filename, mapOpenMode(mode), 0777);
|
|
if (fd >= 0)
|
|
return deFile_createFromHandle((deUintptr)fd);
|
|
else
|
|
return DE_NULL;
|
|
}
|
|
|
|
void deFile_destroy (deFile* file)
|
|
{
|
|
close(file->fd);
|
|
deFree(file);
|
|
}
|
|
|
|
deBool deFile_setFlags (deFile* file, deUint32 flags)
|
|
{
|
|
/* Non-blocking. */
|
|
{
|
|
int oldFlags = fcntl(file->fd, F_GETFL, 0);
|
|
int newFlags = (flags & DE_FILE_NONBLOCKING) ? (oldFlags | O_NONBLOCK) : (oldFlags & ~O_NONBLOCK);
|
|
if (fcntl(file->fd, F_SETFL, newFlags) != 0)
|
|
return DE_FALSE;
|
|
}
|
|
|
|
/* Close on exec. */
|
|
{
|
|
int oldFlags = fcntl(file->fd, F_GETFD, 0);
|
|
int newFlags = (flags & DE_FILE_CLOSE_ON_EXEC) ? (oldFlags | FD_CLOEXEC) : (oldFlags & ~FD_CLOEXEC);
|
|
if (fcntl(file->fd, F_SETFD, newFlags) != 0)
|
|
return DE_FALSE;
|
|
}
|
|
|
|
return DE_TRUE;
|
|
}
|
|
|
|
static int mapSeekPosition (deFilePosition position)
|
|
{
|
|
switch (position)
|
|
{
|
|
case DE_FILEPOSITION_BEGIN: return SEEK_SET;
|
|
case DE_FILEPOSITION_END: return SEEK_END;
|
|
case DE_FILEPOSITION_CURRENT: return SEEK_CUR;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
deBool deFile_seek (deFile* file, deFilePosition base, deInt64 offset)
|
|
{
|
|
return lseek(file->fd, (off_t)offset, mapSeekPosition(base)) >= 0;
|
|
}
|
|
|
|
deInt64 deFile_getPosition (const deFile* file)
|
|
{
|
|
return lseek(file->fd, 0, SEEK_CUR);
|
|
}
|
|
|
|
deInt64 deFile_getSize (const deFile* file)
|
|
{
|
|
deInt64 size = 0;
|
|
deInt64 curPos = lseek(file->fd, 0, SEEK_CUR);
|
|
|
|
if (curPos < 0)
|
|
return -1;
|
|
|
|
size = lseek(file->fd, 0, SEEK_END);
|
|
|
|
if (size < 0)
|
|
return -1;
|
|
|
|
lseek(file->fd, (off_t)curPos, SEEK_SET);
|
|
|
|
return size;
|
|
}
|
|
|
|
static deFileResult mapReadWriteResult (deInt64 numBytes)
|
|
{
|
|
if (numBytes > 0)
|
|
return DE_FILERESULT_SUCCESS;
|
|
else if (numBytes == 0)
|
|
return DE_FILERESULT_END_OF_FILE;
|
|
else
|
|
return errno == EAGAIN ? DE_FILERESULT_WOULD_BLOCK : DE_FILERESULT_ERROR;
|
|
}
|
|
|
|
deFileResult deFile_read (deFile* file, void* buf, deInt64 bufSize, deInt64* numReadPtr)
|
|
{
|
|
deInt64 numRead = read(file->fd, buf, (size_t)bufSize);
|
|
|
|
if (numReadPtr)
|
|
*numReadPtr = numRead;
|
|
|
|
return mapReadWriteResult(numRead);
|
|
}
|
|
|
|
deFileResult deFile_write (deFile* file, const void* buf, deInt64 bufSize, deInt64* numWrittenPtr)
|
|
{
|
|
deInt64 numWritten = write(file->fd, buf, (size_t)bufSize);
|
|
|
|
if (numWrittenPtr)
|
|
*numWrittenPtr = numWritten;
|
|
|
|
return mapReadWriteResult(numWritten);
|
|
}
|
|
|
|
#elif (DE_OS == DE_OS_WIN32)
|
|
|
|
#define VC_EXTRALEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
struct deFile_s
|
|
{
|
|
HANDLE handle;
|
|
};
|
|
|
|
deBool deFileExists (const char* filename)
|
|
{
|
|
return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
|
|
}
|
|
|
|
deBool deDeleteFile (const char* filename)
|
|
{
|
|
return DeleteFile(filename) == TRUE;
|
|
}
|
|
|
|
deFile* deFile_createFromHandle (deUintptr handle)
|
|
{
|
|
deFile* file = (deFile*)deCalloc(sizeof(deFile));
|
|
if (!file)
|
|
{
|
|
CloseHandle((HANDLE)handle);
|
|
return file;
|
|
}
|
|
|
|
file->handle = (HANDLE)handle;
|
|
return file;
|
|
}
|
|
|
|
deFile* deFile_create (const char* filename, deUint32 mode)
|
|
{
|
|
DWORD access = 0;
|
|
DWORD create = OPEN_EXISTING;
|
|
HANDLE handle = DE_NULL;
|
|
|
|
/* Read, write or read and write access is required. */
|
|
DE_ASSERT((mode & DE_FILEMODE_READ) != 0 || ((mode & DE_FILEMODE_WRITE) != 0));
|
|
|
|
/* Create, open or create and open mode is required. */
|
|
DE_ASSERT((mode & DE_FILEMODE_OPEN) != 0 || ((mode & DE_FILEMODE_CREATE) != 0));
|
|
|
|
/* Require write when using create. */
|
|
DE_ASSERT(!(mode & DE_FILEMODE_CREATE) || (mode & DE_FILEMODE_WRITE));
|
|
|
|
/* Require write and open when using truncate */
|
|
DE_ASSERT(!(mode & DE_FILEMODE_TRUNCATE) || ((mode & DE_FILEMODE_WRITE) && (mode & DE_FILEMODE_OPEN)));
|
|
|
|
|
|
if (mode & DE_FILEMODE_READ)
|
|
access |= GENERIC_READ;
|
|
|
|
if (mode & DE_FILEMODE_WRITE)
|
|
access |= GENERIC_WRITE;
|
|
|
|
if ((mode & DE_FILEMODE_TRUNCATE))
|
|
{
|
|
if ((mode & DE_FILEMODE_CREATE) && (mode & DE_FILEMODE_OPEN))
|
|
create = CREATE_ALWAYS;
|
|
else if (mode & DE_FILEMODE_OPEN)
|
|
create = TRUNCATE_EXISTING;
|
|
else
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
else
|
|
{
|
|
if ((mode & DE_FILEMODE_CREATE) && (mode & DE_FILEMODE_OPEN))
|
|
create = OPEN_ALWAYS;
|
|
else if (mode & DE_FILEMODE_CREATE)
|
|
create = CREATE_NEW;
|
|
else if (mode & DE_FILEMODE_OPEN)
|
|
create = OPEN_EXISTING;
|
|
else
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
handle = CreateFile(filename, access, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, DE_NULL, create, FILE_ATTRIBUTE_NORMAL, DE_NULL);
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
return DE_NULL;
|
|
|
|
return deFile_createFromHandle((deUintptr)handle);
|
|
}
|
|
|
|
void deFile_destroy (deFile* file)
|
|
{
|
|
CloseHandle(file->handle);
|
|
deFree(file);
|
|
}
|
|
|
|
deBool deFile_setFlags (deFile* file, deUint32 flags)
|
|
{
|
|
/* Non-blocking. */
|
|
if (flags & DE_FILE_NONBLOCKING)
|
|
return DE_FALSE; /* Not supported. */
|
|
|
|
/* Close on exec. */
|
|
if (!SetHandleInformation(file->handle, HANDLE_FLAG_INHERIT, (flags & DE_FILE_CLOSE_ON_EXEC) ? HANDLE_FLAG_INHERIT : 0))
|
|
return DE_FALSE;
|
|
|
|
return DE_TRUE;
|
|
}
|
|
|
|
deBool deFile_seek (deFile* file, deFilePosition base, deInt64 offset)
|
|
{
|
|
DWORD method = 0;
|
|
LONG lowBits = (LONG)(offset & 0xFFFFFFFFll);
|
|
LONG highBits = (LONG)((offset >> 32) & 0xFFFFFFFFll);
|
|
|
|
switch (base)
|
|
{
|
|
case DE_FILEPOSITION_BEGIN: method = FILE_BEGIN; break;
|
|
case DE_FILEPOSITION_END: method = FILE_END; break;
|
|
case DE_FILEPOSITION_CURRENT: method = FILE_CURRENT; break;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return DE_FALSE;
|
|
}
|
|
|
|
return SetFilePointer(file->handle, lowBits, &highBits, method) != INVALID_SET_FILE_POINTER;
|
|
}
|
|
|
|
deInt64 deFile_getPosition (const deFile* file)
|
|
{
|
|
LONG highBits = 0;
|
|
LONG lowBits = SetFilePointer(file->handle, 0, &highBits, FILE_CURRENT);
|
|
|
|
return (deInt64)(((deUint64)highBits << 32) | (deUint64)lowBits);
|
|
}
|
|
|
|
deInt64 deFile_getSize (const deFile* file)
|
|
{
|
|
DWORD highBits = 0;
|
|
DWORD lowBits = GetFileSize(file->handle, &highBits);
|
|
|
|
return (deInt64)(((deUint64)highBits << 32) | (deUint64)lowBits);
|
|
}
|
|
|
|
static deFileResult mapReadWriteResult (BOOL retVal, DWORD numBytes)
|
|
{
|
|
if (retVal && numBytes > 0)
|
|
return DE_FILERESULT_SUCCESS;
|
|
else if (retVal && numBytes == 0)
|
|
return DE_FILERESULT_END_OF_FILE;
|
|
else
|
|
{
|
|
DWORD error = GetLastError();
|
|
|
|
if (error == ERROR_HANDLE_EOF)
|
|
return DE_FILERESULT_END_OF_FILE;
|
|
else
|
|
return DE_FILERESULT_ERROR;
|
|
}
|
|
}
|
|
|
|
deFileResult deFile_read (deFile* file, void* buf, deInt64 bufSize, deInt64* numReadPtr)
|
|
{
|
|
DWORD bufSize32 = (DWORD)bufSize;
|
|
DWORD numRead32 = 0;
|
|
BOOL result;
|
|
|
|
/* \todo [2011-10-03 pyry] 64-bit IO. */
|
|
DE_ASSERT((deInt64)bufSize32 == bufSize);
|
|
|
|
result = ReadFile(file->handle, buf, bufSize32, &numRead32, DE_NULL);
|
|
|
|
if (numReadPtr)
|
|
*numReadPtr = (deInt64)numRead32;
|
|
|
|
return mapReadWriteResult(result, numRead32);
|
|
}
|
|
|
|
deFileResult deFile_write (deFile* file, const void* buf, deInt64 bufSize, deInt64* numWrittenPtr)
|
|
{
|
|
DWORD bufSize32 = (DWORD)bufSize;
|
|
DWORD numWritten32 = 0;
|
|
BOOL result;
|
|
|
|
/* \todo [2011-10-03 pyry] 64-bit IO. */
|
|
DE_ASSERT((deInt64)bufSize32 == bufSize);
|
|
|
|
result = WriteFile(file->handle, buf, bufSize32, &numWritten32, DE_NULL);
|
|
|
|
if (numWrittenPtr)
|
|
*numWrittenPtr = (deInt64)numWritten32;
|
|
|
|
return mapReadWriteResult(result, numWritten32);
|
|
}
|
|
|
|
#else
|
|
# error Implement deFile for your OS.
|
|
#endif
|