| /*------------------------------------------------------------------------- |
| * 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 |