362 lines
9.1 KiB
C
362 lines
9.1 KiB
C
/*
|
|
Copyright (c) 2008 Giel van Schijndel
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
distribution.
|
|
*/
|
|
|
|
// These are necessary for the `bool' type
|
|
#include "lib/framework/frame.h"
|
|
|
|
#include "physfs_vfs.h"
|
|
#include "sqlite3.h"
|
|
#include <physfs.h>
|
|
#include <assert.h>
|
|
|
|
typedef struct physfs_sqlite3_file physfs_sqlite3_file;
|
|
|
|
/** "Subclassed" sqlite3_file for this PhysicsFS VFS.
|
|
*/
|
|
struct physfs_sqlite3_file
|
|
{
|
|
sqlite3_file SQLite3_file;
|
|
PHYSFS_file* file;
|
|
bool NOOP; /**< Flag which indicates whether all write operations should be no-ops (and reads should fail) */
|
|
};
|
|
|
|
/** Closes the given file and deallocates any associated resources.
|
|
* \param f the physfs_sqlite3_file to close
|
|
* \return SQLITE_OK on success.
|
|
*/
|
|
static int xClose(sqlite3_file* f)
|
|
{
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
if (file->NOOP)
|
|
return SQLITE_OK;
|
|
|
|
if (file->file)
|
|
PHYSFS_close(file->file);
|
|
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/** Reads bytes from the file into the given output buffer.
|
|
* \param f the physfs_sqlite3_file to read from.
|
|
* \param[out] dst the memory buffer to write to.
|
|
* \param iAmt the amount of bytes to read from the file.
|
|
* \param iOfst the (absolute) offset into the file to start reading from.
|
|
* \return SQLITE_OK on success, SQLITE_IOERR_SHORT_READ if we couldn't read
|
|
* the full amount of \c iAmt bytes because EOF was reached, or
|
|
* SQLITE_IOERR_READ for any other error.
|
|
*/
|
|
static int xRead(sqlite3_file* f, void* dst, int iAmt, sqlite3_int64 iOfst)
|
|
{
|
|
PHYSFS_sint64 nRead;
|
|
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
if (file->NOOP)
|
|
return SQLITE_IOERR;
|
|
|
|
/* Seek to the given offset */
|
|
if (!PHYSFS_seek(file->file, iOfst))
|
|
return SQLITE_IOERR_READ;
|
|
|
|
nRead = PHYSFS_read(file->file, dst, 1, iAmt);
|
|
|
|
if (nRead < 0)
|
|
return SQLITE_IOERR_READ;
|
|
else if (nRead < iAmt)
|
|
return SQLITE_IOERR_SHORT_READ;
|
|
else
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/** Dummy write implementation (doesn't do anything at all).
|
|
* \return SQLITE_IOERR_WRITE
|
|
*/
|
|
static int xWrite(sqlite3_file* f, const void* src, int iAmt, sqlite3_int64 iOfst)
|
|
{
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
if (file->NOOP)
|
|
return SQLITE_OK;
|
|
|
|
return SQLITE_IOERR_WRITE;
|
|
}
|
|
|
|
/** Dummy truncate implementation (doesn't do anything at all).
|
|
* \return SQLITE_IOERR_TRUNCATE
|
|
*/
|
|
static int xTruncate(sqlite3_file* f, sqlite3_int64 size)
|
|
{
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
if (file->NOOP)
|
|
return SQLITE_OK;
|
|
|
|
return SQLITE_IOERR_TRUNCATE;
|
|
}
|
|
|
|
/** Dummy sync implementation (doesn't do anything at all).
|
|
* \return SQLITE_IOERR_FSYNC
|
|
*/
|
|
static int xSync(sqlite3_file* f, int flags)
|
|
{
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
if (file->NOOP)
|
|
return SQLITE_OK;
|
|
|
|
return SQLITE_IOERR_FSYNC;
|
|
}
|
|
|
|
/** Determines the size of the given file.
|
|
* \param f the physfs_sqlite3_file to determine the size of.
|
|
* \param[out] pSize to write the size of this file to.
|
|
* \return
|
|
*/
|
|
static int xFileSize(sqlite3_file* f, sqlite3_int64* pSize)
|
|
{
|
|
PHYSFS_sint64 size;
|
|
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
if (file->NOOP)
|
|
return SQLITE_IOERR;
|
|
|
|
size = PHYSFS_fileLength(file->file);
|
|
|
|
if (size < 0)
|
|
return SQLITE_IOERR_FSTAT;
|
|
|
|
*pSize = size;
|
|
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int xLock(sqlite3_file* f, int level)
|
|
{
|
|
switch (level)
|
|
{
|
|
case SQLITE_LOCK_NONE:
|
|
case SQLITE_LOCK_SHARED:
|
|
return SQLITE_OK;
|
|
|
|
case SQLITE_LOCK_RESERVED:
|
|
case SQLITE_LOCK_PENDING:
|
|
case SQLITE_LOCK_EXCLUSIVE:
|
|
default:
|
|
return SQLITE_IOERR_RDLOCK;
|
|
}
|
|
}
|
|
|
|
static int xUnlock(sqlite3_file* f, int level)
|
|
{
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int xCheckReservedLock(sqlite3_file* f)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int xFileControl(sqlite3_file* f, int op, void *pArg)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int xSectorSize(sqlite3_file* f)
|
|
{
|
|
return 512;
|
|
}
|
|
|
|
static int xDeviceCharacteristics(sqlite3_file* f)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static const sqlite3_io_methods physfs_sqlite3_io_methods =
|
|
{
|
|
1, /**< iVersion */
|
|
xClose, /**< Closes the physfs_sqlite3_file */
|
|
xRead, /**< Reads from the physfs_sqlite3_file */
|
|
xWrite, /**< Intended to write from the physfs_sqlite3_file */
|
|
xTruncate, /**< Intended to truncate the physfs_sqlite3_file */
|
|
xSync, /**< Intended to flush data out of OS cache into non-volatile memory */
|
|
xFileSize, /**< Deterimines the physfs_sqlite3_file's size */
|
|
xLock, /**< Acquires a lock on the physfs_sqlite3_file */
|
|
xUnlock, /**< Releases a lock on the physfs_sqlite3_file */
|
|
xCheckReservedLock, /**< Checks whether a "reserved" (or higher) level lock is acquired on this physfs_sqlite3_file */
|
|
xFileControl, /**< Intended to execute the given opcode */
|
|
xSectorSize, /**< Determines the size of sectors for the underlying filesystem */
|
|
xDeviceCharacteristics, /**< Returns a bitmask describing the underlying filesystem's characteristics */
|
|
};
|
|
|
|
static int xOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* f, int flags, int* pOutFlags)
|
|
{
|
|
physfs_sqlite3_file * const file = (physfs_sqlite3_file * const)f;
|
|
assert(&file->SQLite3_file == f);
|
|
|
|
/* Assign the "overloaded" I/O functions to this file object */
|
|
file->SQLite3_file.pMethods = &physfs_sqlite3_io_methods;
|
|
|
|
/* We don't support journals in this implementation */
|
|
if (flags & SQLITE_OPEN_MAIN_JOURNAL
|
|
|| flags & SQLITE_OPEN_TEMP_JOURNAL
|
|
|| flags & SQLITE_OPEN_MASTER_JOURNAL
|
|
|| flags & SQLITE_OPEN_SUBJOURNAL)
|
|
{
|
|
file->file = 0;
|
|
file->NOOP = true;
|
|
}
|
|
else /* if (flags & SQLITE_OPEN_MAIN_DB
|
|
|| flags & SQLITE_OPEN_TEMP_DB
|
|
|| flags & SQLITE_OPEN_TRANSIENT_DB) */
|
|
{
|
|
file->file = PHYSFS_openRead(zName);
|
|
file->NOOP = false;
|
|
|
|
if (!file->file)
|
|
return SQLITE_IOERR;
|
|
}
|
|
|
|
*pOutFlags = SQLITE_OPEN_READONLY;
|
|
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int xDelete(sqlite3_vfs* pVfs, const char* zName, int syncDir)
|
|
{
|
|
if (PHYSFS_delete(zName))
|
|
return SQLITE_OK;
|
|
else
|
|
return SQLITE_IOERR_DELETE;
|
|
}
|
|
|
|
static int xAccess(sqlite3_vfs* pVfs, const char* zName, int flags)
|
|
{
|
|
switch (flags)
|
|
{
|
|
case SQLITE_ACCESS_EXISTS:
|
|
return PHYSFS_exists(zName);
|
|
|
|
case SQLITE_ACCESS_READ:
|
|
{
|
|
PHYSFS_file* f = PHYSFS_openRead(zName);
|
|
if (!f)
|
|
return false;
|
|
|
|
PHYSFS_close(f);
|
|
return true;
|
|
}
|
|
|
|
case SQLITE_ACCESS_READWRITE:
|
|
return false;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static int xGetTempname(sqlite3_vfs* pVfs, int nOut, char* zOut)
|
|
{
|
|
return SQLITE_IOERR;
|
|
}
|
|
|
|
/** \return non-zero when no truncation occurred, zero otherwise.
|
|
*/
|
|
static int xFullPathname(sqlite3_vfs* pVfs, const char* zName, int nOut, char* zOut)
|
|
{
|
|
return (strlcpy(zOut, zName, nOut) < nOut) ? SQLITE_OK : SQLITE_IOERR;
|
|
}
|
|
|
|
static void* xDlOpen(sqlite3_vfs* pVfs, const char* zFilename)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void xDlError(sqlite3_vfs* pVfs, int nByte, char* zErrMsg)
|
|
{
|
|
strlcpy(zErrMsg, "DlOpen and DlSym API isn't supported for this (PhysicsFS \"physfs\") VFS.", nByte);
|
|
}
|
|
|
|
static void *xDlSym(sqlite3_vfs* pVfs, void* dl, const char* zSymbol)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void xDlClose(sqlite3_vfs* pVfs, void* dl)
|
|
{
|
|
}
|
|
|
|
static int xRandomness(sqlite3_vfs* pVfs, int nByte, char* zOut)
|
|
{
|
|
return SQLITE_IOERR;
|
|
}
|
|
|
|
static int xSleep(sqlite3_vfs* pVfs, int microseconds)
|
|
{
|
|
return SQLITE_IOERR;
|
|
}
|
|
|
|
static int xCurrentTime(sqlite3_vfs* pVfs, double* curTime)
|
|
{
|
|
return SQLITE_IOERR;
|
|
}
|
|
|
|
static sqlite3_vfs physfs_sqlite3_vfs =
|
|
{
|
|
1, /**< Structure version number */
|
|
sizeof(physfs_sqlite3_vfs), /**< Size of subclassed sqlite3_file */
|
|
256, /**< Maximum file pathname length */
|
|
0, /**< Next registered VFS (managed by SQLite) */
|
|
"physfs", /**< Name of this virtual file system */
|
|
0, /**< Pointer to application-specific data */
|
|
xOpen,
|
|
xDelete,
|
|
xAccess,
|
|
xGetTempname,
|
|
xFullPathname,
|
|
xDlOpen,
|
|
xDlError,
|
|
xDlSym,
|
|
xDlClose,
|
|
xRandomness,
|
|
xSleep,
|
|
xCurrentTime,
|
|
};
|
|
|
|
void sqlite3_register_physfs_vfs(int makeDefault)
|
|
{
|
|
sqlite3_vfs_register(&physfs_sqlite3_vfs, makeDefault);
|
|
}
|
|
|
|
void sqlite3_unregister_physfs_vfs()
|
|
{
|
|
sqlite3_vfs_unregister(&physfs_sqlite3_vfs);
|
|
}
|