implemented lba VFS

This commit is contained in:
Jack Andersen 2015-05-21 22:21:44 -10:00
parent f02aa1ca8f
commit db0ce36b90
11 changed files with 698 additions and 17 deletions

View File

@ -2095,7 +2095,7 @@ HIDE_UNDOC_RELATIONS = YES
# set to NO # set to NO
# The default value is: NO. # The default value is: NO.
HAVE_DOT = NO HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of # to run in parallel. When set to 0 doxygen will base this on the number of
@ -2161,7 +2161,7 @@ GROUP_GRAPHS = YES
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = NO UML_LOOK = YES
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the # If the UML_LOOK tag is enabled, the fields and methods are shown inside the
# class node. If there are many fields or methods and many nodes the graph may # class node. If there are many fields or methods and many nodes the graph may

View File

@ -6,7 +6,7 @@
#include "STRG.hpp" #include "STRG.hpp"
#include "TXTR.hpp" #include "TXTR.hpp"
const HECLDatabase::RegistryEntry DATASPEC_TYPES[] const HECLDatabase::RegistryEntry DATASPEC_TYPE_REGISTRY[]
{ {
REGISTRY_ENTRY("DUMB", CDUMBProject, CDUMBRuntime), REGISTRY_ENTRY("DUMB", CDUMBProject, CDUMBRuntime),
REGISTRY_ENTRY("HMDL", CHMDLProject, CHMDLRuntime), REGISTRY_ENTRY("HMDL", CHMDLProject, CHMDLRuntime),

View File

@ -69,6 +69,90 @@ public:
inline bool operator>=(ObjectHash& other) {return hash >= other.hash;} inline bool operator>=(ObjectHash& other) {return hash >= other.hash;}
}; };
inline int16_t bswap(int16_t val)
{
#if __GNUC__
return __builtin_bswap16(val);
#elif _WIN32
return _byteswap_ushort(val);
#else
return (val = (val << 8) | ((val >> 8) & 0xFF));
#endif
}
inline uint16_t bswap(uint16_t val)
{
#if __GNUC__
return __builtin_bswap16(val);
#elif _WIN32
return _byteswap_ushort(val);
#else
return (val = (val << 8) | ((val >> 8) & 0xFF));
#endif
}
inline int32_t bswap(int32_t val)
{
#if __GNUC__
return __builtin_bswap32(val);
#elif _WIN32
return _byteswap_ulong(val);
#else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val;
#endif
}
inline uint32_t bswap(uint32_t val)
{
#if __GNUC__
return __builtin_bswap32(val);
#elif _WIN32
return _byteswap_ulong(val);
#else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val;
#endif
}
inline int64_t bswap(int64_t val)
{
#if __GNUC__
return __builtin_bswap64(val);
#elif _WIN32
return _byteswap_uint64(val);
#else
return (val = ((atInt64)((((atInt64)(val) & 0xFF00000000000000ULL) >> 56) |
(((atInt64)(val) & 0x00FF000000000000ULL) >> 40) |
(((atInt64)(val) & 0x0000FF0000000000ULL) >> 24) |
(((atInt64)(val) & 0x000000FF00000000ULL) >> 8) |
(((atInt64)(val) & 0x00000000FF000000ULL) << 8) |
(((atInt64)(val) & 0x0000000000FF0000ULL) << 24) |
(((atInt64)(val) & 0x000000000000FF00ULL) << 40) |
(((atInt64)(val) & 0x00000000000000FFULL) << 56))));
#endif
}
inline uint64_t bswap(uint64_t val)
{
#if __GNUC__
return __builtin_bswap64(val);
#elif _WIN32
return _byteswap_uint64(val);
#else
return (val = ((atInt64)((((atInt64)(val) & 0xFF00000000000000ULL) >> 56) |
(((atInt64)(val) & 0x00FF000000000000ULL) >> 40) |
(((atInt64)(val) & 0x0000FF0000000000ULL) >> 24) |
(((atInt64)(val) & 0x000000FF00000000ULL) >> 8) |
(((atInt64)(val) & 0x00000000FF000000ULL) << 8) |
(((atInt64)(val) & 0x0000000000FF0000ULL) << 24) |
(((atInt64)(val) & 0x000000000000FF00ULL) << 40) |
(((atInt64)(val) & 0x00000000000000FFULL) << 56))));
#endif
}
} }
#endif // HECL_HPP #endif // HECL_HPP

View File

@ -404,7 +404,7 @@ public:
* intermediates into a packed database file located alongside the specified * intermediates into a packed database file located alongside the specified
* directory. This is a similar process to 'linking' in software development. * directory. This is a similar process to 'linking' in software development.
* *
* Part of this process involves calling IDataObject::_gatherDeps() to calculate * Part of this process involves calling CProjectObject::_gatherDeps() to calculate
* object dependencies. This makes package-assembly simple, as dependencies will * object dependencies. This makes package-assembly simple, as dependencies will
* automatically be added as needed. The frontend needn't be concerned about * automatically be added as needed. The frontend needn't be concerned about
* gathering leaf-objects buried in corners of the working directory. * gathering leaf-objects buried in corners of the working directory.

View File

@ -38,12 +38,20 @@ public:
m_cookedDb = new CLooseDatabase(m_rootPath + "/.hecl/cooked.db", IDatabase::A_READWRITE); m_cookedDb = new CLooseDatabase(m_rootPath + "/.hecl/cooked.db", IDatabase::A_READWRITE);
} }
~CProject()
{
delete m_mainDb;
delete m_cookedDb;
}
IDatabase* mainDatabase() const IDatabase* mainDatabase() const
{ {
return m_mainDb;
} }
IDatabase* cookedDatabase() const IDatabase* cookedDatabase() const
{ {
return m_cookedDb;
} }
void registerLogger(HECL::TLogger logger) void registerLogger(HECL::TLogger logger)

View File

@ -16,17 +16,20 @@ namespace HECLDatabase
static const char* skDBINIT = static const char* skDBINIT =
"PRAGMA foreign_keys = ON;\n" "PRAGMA foreign_keys = ON;\n"
"CREATE TABLE IF NOT EXISTS objects(rowid INTEGER PRIMARY KEY," "CREATE TABLE IF NOT EXISTS objects(rowid INTEGER PRIMARY KEY,"
"name," "path,"
"subpath"
"type4cc UNSIGNED INTEGER," "type4cc UNSIGNED INTEGER,"
"hash64 UNSIGNED INTEGER," "hash64 INTEGER);\n"
"compLen UNSIGNED INTEGER,"
"decompLen UNSIGNED INTEGER);\n"
"CREATE INDEX IF NOT EXISTS nameidx ON objects(name);\n" "CREATE INDEX IF NOT EXISTS nameidx ON objects(name);\n"
"CREATE TABLE IF NOT EXISTS deplinks(groupId," "CREATE TABLE IF NOT EXISTS deplinks(groupId,"
"objId REFERENCES objects(rowid) ON DELETE CASCADE," "objId REFERENCES objects(rowid) ON DELETE CASCADE,"
"UNIQUE (groupId, objId) ON CONFLICT IGNORE);\n" "UNIQUE (groupId, objId) ON CONFLICT IGNORE);\n"
"CREATE INDEX IF NOT EXISTS grpidx ON deplinks(groupId);\n" "CREATE INDEX IF NOT EXISTS grpidx ON deplinks(groupId);\n"
"CREATE INDEX IF NOT EXISTS depidx ON deplinks(objId);\n"; "CREATE INDEX IF NOT EXISTS depidx ON deplinks(objId);\n"
"CREATE TABLE IF NOT EXISTS cooked(objid INTEGER PRIMARY KEY REFERENCES objects(rowid) ON DELETE CASCADE,"
"offset UNSIGNED INTEGER,"
"compLen UNSIGNED INTEGER,"
"decompLen UNSIGNED INTEGER);\n";
#define PREPSTMT(stmtSrc, outVar)\ #define PREPSTMT(stmtSrc, outVar)\
if (sqlite3_prepare_v2(m_db, stmtSrc, 0, &outVar, NULL) != SQLITE_OK)\ if (sqlite3_prepare_v2(m_db, stmtSrc, 0, &outVar, NULL) != SQLITE_OK)\

View File

@ -7,6 +7,8 @@ HEADERS += \
SOURCES += \ SOURCES += \
$$PWD/HECLDatabase.cpp \ $$PWD/HECLDatabase.cpp \
$$PWD/sqlite_hecl_mem_vfs.c \
$$PWD/CRuntime.cpp \ $$PWD/CRuntime.cpp \
$$PWD/CProject.cpp $$PWD/CProject.cpp \
$$PWD/sqlite_hecl_mem_vfs.c \
$$PWD/sqlite_hecl_memlba_vfs.c \
$$PWD/sqlite_hecl_memlba_make.c

View File

@ -257,10 +257,10 @@ static int memOpen(
int* pOutFlags int* pOutFlags
) )
{ {
if(flags != SQLITE_OPEN_MAIN_DB) if ((flags & SQLITE_OPEN_MAIN_DB) != SQLITE_OPEN_MAIN_DB)
{ {
fprintf(stderr, "the sqlite hecl mem VFS only supports main-db writing\n"); fprintf(stderr, "the sqlite hecl mem VFS only supports main-db reading/writing\n");
abort(); return SQLITE_CANTOPEN;
} }
mem_file* p2 = (mem_file*)pFile; mem_file* p2 = (mem_file*)pFile;
memset(p2, 0, sizeof(*p2)); memset(p2, 0, sizeof(*p2));

View File

@ -0,0 +1,108 @@
#include "sqlite_hecl_vfs.h"
#include <zlib/zlib.h>
#include <stdint.h>
#include <stdbool.h>
/*
* Block-compression LBA generator used for storing packed sqlite3 database
*/
#define BLOCK_SIZE 0x4000
#define ROUND_UP_BLOCK(val) (((val) + (BLOCK_SIZE-1)) & ~(BLOCK_SIZE-1))
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static inline uint32_t makeu32(uint32_t val, bool bigEndian)
{
if (!bigEndian)
return val;
#if __GNUC__
return __builtin_bswap32(val);
#elif _WIN32
return _byteswap_ulong(val);
#else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val;
#endif
}
#else
static inline uint32_t makeu32(uint32_t val, bool bigEndian)
{
if (bigEndian)
return val;
#if __GNUC__
return __builtin_bswap32(val);
#elif _WIN32
return _byteswap_ulong(val);
#else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val;
#endif
}
#endif
/* Useful macros used in several places */
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
void sqlite_hecl_memlba_make(FILE* fout, void* bufin, size_t bufinLen, bool bigEndian)
{
unsigned i;
/* Magic */
fwrite("HLPK", 1, 4, fout);
/* Block size */
uint32_t blockSize_s = makeu32(BLOCK_SIZE, bigEndian);
fwrite(&blockSize_s, 1, 4, fout);
/* Block count */
size_t blockCount = ROUND_UP_BLOCK(bufinLen) / BLOCK_SIZE;
uint32_t blockCount_s = makeu32(blockCount, bigEndian);
fwrite(&blockCount_s, 1, 4, fout);
/* Header+TOC+DB Size */
fwrite("\0\0\0\0", 1, 4, fout);
/* Block TOC buffer and file-space */
uint32_t* blockTOC = calloc(blockCount+1, 4);
for (i=0 ; i<blockCount+1 ; ++i)
fwrite("\0\0\0\0", 1, 4, fout);
/* Block-compression context */
z_stream zstrm = {};
deflateInit(&zstrm, 7);
zstrm.next_in = bufin;
/* Compress! */
size_t curOff = 16 + (blockCount+1) * 4;
size_t remSz = bufinLen;
for (i=0 ; i<blockCount ; ++i)
{
unsigned char compBuf[BLOCK_SIZE*2];
zstrm.avail_in = MIN(remSz, BLOCK_SIZE);
zstrm.avail_out = BLOCK_SIZE*2;
zstrm.next_out = compBuf;
deflate(&zstrm, Z_FINISH);
fwrite(compBuf, 1, zstrm.total_out, fout);
blockTOC[i] = makeu32(curOff, bigEndian);
curOff += zstrm.total_out;
remSz -= zstrm.total_in;
deflateReset(&zstrm);
}
/* Write Header+TOC+DB Size */
fseek(fout, 12, SEEK_SET);
uint32_t headSz_s = makeu32(curOff, bigEndian);
fwrite(&headSz_s, 1, 4, fout);
/* Write TOC */
blockTOC[blockCount] = headSz_s;
fwrite(blockTOC, 4, blockCount+1, fout);
/* Cleanup */
deflateEnd(&zstrm);
free(blockTOC);
}

View File

@ -0,0 +1,472 @@
#include "sqlite_hecl_vfs.h"
#include "sqlite3.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <zlib/zlib.h>
/*
* Modified test_onefile.c VFS for sqlite3
*
* This VFS gets registered with sqlite to access an in-memory,
* block-compressed LBA. It's designed for read-only access of
* a packed object-database.
*
* Journal and temp read/write is unsupported and will call abort
* if attempted.
*/
/*
* App-supplied pointer to head buffer (Header+TOC+DB)
*/
static void* HEAD_BUF = NULL;
#define BLOCK_SLOTS 4
typedef struct memlba_file memlba_file;
struct memlba_file
{
sqlite3_file base;
struct
{
char magic[4];
uint32_t blockSize;
uint32_t blockCount;
uint32_t headSz;
uint32_t blockTOC[];
}* headBuf;
void* cachedBlockBufs[BLOCK_SLOTS];
/* All initialized to -1 */
int cachedBlockIndices[BLOCK_SLOTS];
/* Ages start at 0, newly inserted block is 1.
* Non-0 blocks incremented on every insertion.
* If any slot is BLOCK_SLOTS upon insertion, surrounding blocks
* are incremented and that slot is reset to 1 (oldest-block caching)
*/
int cachedBlockAges[BLOCK_SLOTS];
z_stream zstrm;
};
static int newBlockSlot(memlba_file* file)
{
unsigned i;
for (i=0 ; i<BLOCK_SLOTS ; ++i)
if (file->cachedBlockAges[i] != 0)
++file->cachedBlockAges[i];
for (i=0 ; i<BLOCK_SLOTS ; ++i)
if (file->cachedBlockAges[i] == 0)
{
file->cachedBlockAges[i] = 1;
return i;
}
for (i=0 ; i<BLOCK_SLOTS ; ++i)
if (file->cachedBlockAges[i] == BLOCK_SLOTS+1)
{
file->cachedBlockAges[i] = 1;
return i;
}
/* Shouldn't happen (fallback) */
for (i=1 ; i<BLOCK_SLOTS ; ++i)
{
file->cachedBlockAges[i] = 0;
file->cachedBlockIndices[i] = -1;
}
file->cachedBlockAges[0] = 1;
return 0;
}
static void decompressBlock(memlba_file* file, int blockIdx, int targetSlot)
{
if (blockIdx >= file->headBuf->blockCount)
{
fprintf(stderr, "exceeded memlba block range");
abort();
}
void* dbBlock = ((void*)file->headBuf) + file->headBuf->blockTOC[blockIdx];
file->zstrm.next_in = dbBlock;
file->zstrm.avail_in = file->headBuf->blockTOC[blockIdx+1] - file->headBuf->blockTOC[blockIdx];
file->zstrm.next_out = file->cachedBlockBufs[targetSlot];
file->zstrm.avail_out = file->headBuf->blockSize;
inflate(&file->zstrm, Z_FINISH);
inflateReset(&file->zstrm);
}
static int getBlockSlot(memlba_file* file, int blockIdx)
{
unsigned i;
for (i=0 ; i<BLOCK_SLOTS ; ++i)
if (file->cachedBlockIndices[i] != blockIdx)
return i;
int newSlot = newBlockSlot(file);
file->cachedBlockIndices[newSlot] = blockIdx;
decompressBlock(file, blockIdx, newSlot);
return newSlot;
}
/*
** Method declarations for memlba_file.
*/
static int memlbaClose(sqlite3_file*);
static int memlbaRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int memlbaWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
static int memlbaTruncate(sqlite3_file*, sqlite3_int64 size);
static int memlbaSync(sqlite3_file*, int flags);
static int memlbaFileSize(sqlite3_file*, sqlite3_int64* pSize);
static int memlbaLock(sqlite3_file*, int);
static int memlbaUnlock(sqlite3_file*, int);
static int memlbaCheckReservedLock(sqlite3_file*, int* pResOut);
static int memlbaFileControl(sqlite3_file*, int op, void* pArg);
static int memlbaSectorSize(sqlite3_file*);
static int memlbaDeviceCharacteristics(sqlite3_file*);
/*
** Method declarations for fs_vfs.
*/
static int memlbaOpen(sqlite3_vfs*, const char*, sqlite3_file*, int , int*);
static int memlbaDelete(sqlite3_vfs*, const char* zName, int syncDir);
static int memlbaAccess(sqlite3_vfs*, const char* zName, int flags, int*);
static int memlbaFullPathname(sqlite3_vfs*, const char* zName, int nOut, char* zOut);
static void* memlbaDlOpen(sqlite3_vfs*, const char* zFilename);
static void memlbaDlError(sqlite3_vfs*, int nByte, char* zErrMsg);
static void (*memlbaDlSym(sqlite3_vfs*, void*, const char* zSymbol))(void);
static void memlbaDlClose(sqlite3_vfs*, void*);
static int memlbaRandomness(sqlite3_vfs*, int nByte, char* zOut);
static int memlbaSleep(sqlite3_vfs*, int microseconds);
static int memlbaCurrentTime(sqlite3_vfs*, double*);
static sqlite3_vfs memlba_vfs =
{
1, /* iVersion */
0, /* szOsFile */
0, /* mxPathname */
0, /* pNext */
"hecl_memlba", /* zName */
0, /* pAppData */
memlbaOpen, /* xOpen */
memlbaDelete, /* xDelete */
memlbaAccess, /* xAccess */
memlbaFullPathname, /* xFullPathname */
memlbaDlOpen, /* xDlOpen */
memlbaDlError, /* xDlError */
memlbaDlSym, /* xDlSym */
memlbaDlClose, /* xDlClose */
memlbaRandomness, /* xRandomness */
memlbaSleep, /* xSleep */
memlbaCurrentTime, /* xCurrentTime */
0 /* xCurrentTimeInt64 */
};
static sqlite3_io_methods memlba_io_methods =
{
1, /* iVersion */
memlbaClose, /* xClose */
memlbaRead, /* xRead */
memlbaWrite, /* xWrite */
memlbaTruncate, /* xTruncate */
memlbaSync, /* xSync */
memlbaFileSize, /* xFileSize */
memlbaLock, /* xLock */
memlbaUnlock, /* xUnlock */
memlbaCheckReservedLock, /* xCheckReservedLock */
memlbaFileControl, /* xFileControl */
memlbaSectorSize, /* xSectorSize */
memlbaDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
0,
0
};
/* Useful macros used in several places */
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
/*
** Close a memlba-file.
*/
static int memlbaClose(sqlite3_file* pFile)
{
memlba_file* pTmp = (memlba_file*)pFile;
free(pTmp->headBuf);
free(pTmp->cachedBlockBufs[0]);
inflateEnd(&pTmp->zstrm);
return SQLITE_OK;
}
/*
** Read data from a memlba-file.
*/
static int memlbaRead(
sqlite3_file* pFile,
void* zBuf,
int iAmt,
sqlite_int64 iOfst
)
{
memlba_file* pTmp = (memlba_file*)pFile;
unsigned blockIdx = iOfst / pTmp->headBuf->blockSize;
unsigned firstOff = iOfst % pTmp->headBuf->blockSize;
unsigned firstRemBytes = pTmp->headBuf->blockSize - firstOff;
int slot = getBlockSlot(pTmp, blockIdx);
unsigned toRead = MIN(iAmt, firstRemBytes);
memcpy(zBuf, pTmp->cachedBlockBufs[slot] + firstOff, toRead);
iAmt -= toRead;
zBuf += toRead;
while (iAmt)
{
slot = getBlockSlot(pTmp, ++blockIdx);
toRead = MIN(iAmt, pTmp->headBuf->blockSize);
memcpy(zBuf, pTmp->cachedBlockBufs[slot], toRead);
iAmt -= toRead;
zBuf += toRead;
}
return SQLITE_OK;
}
/*
** Write data to a memlba-file.
*/
static int memlbaWrite(
sqlite3_file* pFile,
const void* zBuf,
int iAmt,
sqlite_int64 iOfst
)
{
return SQLITE_OK;
}
/*
** Truncate a memlba-file.
*/
static int memlbaTruncate(sqlite3_file* pFile, sqlite_int64 size)
{
memlba_file* pTmp = (memlba_file*)pFile;
return SQLITE_OK;
}
/*
** Sync a memlba-file.
*/
static int memlbaSync(sqlite3_file* pFile, int flags)
{
return SQLITE_OK;
}
/*
** Return the current file-size of a memlba-file.
*/
static int memlbaFileSize(sqlite3_file* pFile, sqlite_int64* pSize)
{
memlba_file* pTmp = (memlba_file*)pFile;
*pSize = pTmp->headBuf->headSz - pTmp->headBuf->blockTOC[0];
return SQLITE_OK;
}
/*
** Lock a memlba-file.
*/
static int memlbaLock(sqlite3_file* pFile, int eLock)
{
return SQLITE_OK;
}
/*
** Unlock a memlba-file.
*/
static int memlbaUnlock(sqlite3_file* pFile, int eLock)
{
return SQLITE_OK;
}
/*
** Check if another file-handle holds a RESERVED lock on a memlba-file.
*/
static int memlbaCheckReservedLock(sqlite3_file* pFile, int* pResOut)
{
*pResOut = 0;
return SQLITE_OK;
}
/*
** File control method. For custom operations on a memlba-file.
*/
static int memlbaFileControl(sqlite3_file* pFile, int op, void* pArg)
{
return SQLITE_OK;
}
/*
** Return the sector-size in bytes for a memlba-file.
*/
static int memlbaSectorSize(sqlite3_file* pFile)
{
return 0;
}
/*
** Return the device characteristic flags supported by a memlba-file.
*/
static int memlbaDeviceCharacteristics(sqlite3_file* pFile)
{
return 0;
}
/*
** Open an memlba file handle.
*/
static int memlbaOpen(
sqlite3_vfs* pVfs,
const char* zName,
sqlite3_file* pFile,
int flags,
int* pOutFlags
)
{
if ((flags & SQLITE_OPEN_MAIN_DB) != SQLITE_OPEN_MAIN_DB ||
(flags & SQLITE_OPEN_READONLY) != SQLITE_OPEN_READONLY)
{
fprintf(stderr, "the sqlite hecl memlba VFS only supports main-db reading\n");
return SQLITE_CANTOPEN;
}
memlba_file* p2 = (memlba_file*)pFile;
memset(p2, 0, sizeof(*p2));
p2->base.pMethods = &memlba_io_methods;
inflateInit(&p2->zstrm);
p2->headBuf = HEAD_BUF;
unsigned i;
void* blockBufs = calloc(BLOCK_SLOTS, p2->headBuf->blockSize);
for (i=0 ; i<BLOCK_SLOTS ; ++i)
{
p2->cachedBlockBufs[i] = blockBufs + p2->headBuf->blockSize * i;
}
return SQLITE_OK;
}
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** returning.
*/
static int memlbaDelete(sqlite3_vfs* pVfs, const char* zPath, int dirSync)
{
return SQLITE_OK;
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int memlbaAccess(
sqlite3_vfs* pVfs,
const char* zPath,
int flags,
int* pResOut
)
{
if(flags & SQLITE_ACCESS_READ | SQLITE_ACCESS_READWRITE)
return 1;
return 0;
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (FS_MAX_PATHNAME+1) bytes.
*/
static int memlbaFullPathname(
sqlite3_vfs* pVfs, /* Pointer to vfs object */
const char* zPath, /* Possibly relative input path */
int nOut, /* Size of output buffer in bytes */
char* zOut) /* Output buffer */
{
strncpy(zOut, zPath, nOut);
return SQLITE_OK;
}
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void* memlbaDlOpen(sqlite3_vfs* pVfs, const char* zPath)
{
return NULL;
}
/*
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
** utf-8 string describing the most recent error encountered associated
** with dynamic libraries.
*/
static void memlbaDlError(sqlite3_vfs* pVfs, int nByte, char* zErrMsg)
{
}
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void (*memlbaDlSym(sqlite3_vfs* pVfs, void* pH, const char* zSym))(void)
{
}
/*
** Close the dynamic library handle pHandle.
*/
static void memlbaDlClose(sqlite3_vfs* pVfs, void* pHandle)
{
}
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int memlbaRandomness(sqlite3_vfs* pVfs, int nByte, char* zBufOut)
{
for(int i = 0 ; i < nByte ; ++i)
zBufOut[i] = rand();
return nByte;
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int memlbaSleep(sqlite3_vfs* pVfs, int nMicro)
{
int seconds = (nMicro + 999999) / 1000000;
sleep(seconds);
return seconds * 1000000;
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int memlbaCurrentTime(sqlite3_vfs* pVfs, double* pTimeOut)
{
*pTimeOut = 0.0;
return 0;
}
/*
** This procedure registers the memlba vfs with SQLite. If the argument is
** true, the memlba vfs becomes the new default vfs. It is the only publicly
** available function in this file.
*/
int sqlite_hecl_memlba_vfs_register(void* headBuf)
{
HEAD_BUF = headBuf;
if(memlba_vfs.szOsFile) return SQLITE_OK;
memlba_vfs.szOsFile = sizeof(memlba_file);
return sqlite3_vfs_register(&memlba_vfs, 0);
}

View File

@ -5,10 +5,14 @@
extern "C" { extern "C" {
#endif #endif
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
typedef void(*TCloseCallback)(void* buf, size_t bufLen, void* ctx); typedef void(*TCloseCallback)(void* buf, size_t bufLen, void* ctx);
int sqlite_hecl_mem_vfs_register(TCloseCallback closeCb, void* ctx); int sqlite_hecl_mem_vfs_register(TCloseCallback closeCb, void* ctx);
int sqlite_hecl_memlba_vfs_register(TCloseCallback closeCb, void* ctx); int sqlite_hecl_memlba_vfs_register(void* headBuf);
void sqlite_hecl_memlba_make(FILE* fout, void* bufin, size_t bufinLen, bool bigEndian);
#ifdef __cplusplus #ifdef __cplusplus
} }