diff --git a/hecl/Doxyfile b/hecl/Doxyfile index 0c927847d..edf7d6418 100644 --- a/hecl/Doxyfile +++ b/hecl/Doxyfile @@ -2095,7 +2095,7 @@ HIDE_UNDOC_RELATIONS = YES # set to 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 # 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. # 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 # class node. If there are many fields or methods and many nodes the graph may diff --git a/hecl/dataspec/dataspec.cpp b/hecl/dataspec/dataspec.cpp index ec950ac43..d35c170f9 100644 --- a/hecl/dataspec/dataspec.cpp +++ b/hecl/dataspec/dataspec.cpp @@ -6,7 +6,7 @@ #include "STRG.hpp" #include "TXTR.hpp" -const HECLDatabase::RegistryEntry DATASPEC_TYPES[] +const HECLDatabase::RegistryEntry DATASPEC_TYPE_REGISTRY[] { REGISTRY_ENTRY("DUMB", CDUMBProject, CDUMBRuntime), REGISTRY_ENTRY("HMDL", CHMDLProject, CHMDLRuntime), diff --git a/hecl/include/HECL.hpp b/hecl/include/HECL.hpp index fc2290739..6cb53262c 100644 --- a/hecl/include/HECL.hpp +++ b/hecl/include/HECL.hpp @@ -69,6 +69,90 @@ public: 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 diff --git a/hecl/include/HECLDatabase.hpp b/hecl/include/HECLDatabase.hpp index 37008930c..52f8b9573 100644 --- a/hecl/include/HECLDatabase.hpp +++ b/hecl/include/HECLDatabase.hpp @@ -404,7 +404,7 @@ public: * intermediates into a packed database file located alongside the specified * 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 * automatically be added as needed. The frontend needn't be concerned about * gathering leaf-objects buried in corners of the working directory. diff --git a/hecl/lib/database/CProject.cpp b/hecl/lib/database/CProject.cpp index 42df77544..65b7a5ac4 100644 --- a/hecl/lib/database/CProject.cpp +++ b/hecl/lib/database/CProject.cpp @@ -38,12 +38,20 @@ public: m_cookedDb = new CLooseDatabase(m_rootPath + "/.hecl/cooked.db", IDatabase::A_READWRITE); } + ~CProject() + { + delete m_mainDb; + delete m_cookedDb; + } + IDatabase* mainDatabase() const { + return m_mainDb; } IDatabase* cookedDatabase() const { + return m_cookedDb; } void registerLogger(HECL::TLogger logger) diff --git a/hecl/lib/database/CSQLite.hpp b/hecl/lib/database/CSQLite.hpp index 369f2a803..205ebac6c 100644 --- a/hecl/lib/database/CSQLite.hpp +++ b/hecl/lib/database/CSQLite.hpp @@ -16,17 +16,20 @@ namespace HECLDatabase static const char* skDBINIT = "PRAGMA foreign_keys = ON;\n" "CREATE TABLE IF NOT EXISTS objects(rowid INTEGER PRIMARY KEY," - "name," + "path," + "subpath" "type4cc UNSIGNED INTEGER," - "hash64 UNSIGNED INTEGER," - "compLen UNSIGNED INTEGER," - "decompLen UNSIGNED INTEGER);\n" + "hash64 INTEGER);\n" "CREATE INDEX IF NOT EXISTS nameidx ON objects(name);\n" -"CREATE TABLE IF NOT EXISTS deplinks(groupId, " - "objId REFERENCES objects(rowid) ON DELETE CASCADE, " +"CREATE TABLE IF NOT EXISTS deplinks(groupId," + "objId REFERENCES objects(rowid) ON DELETE CASCADE," "UNIQUE (groupId, objId) ON CONFLICT IGNORE);\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)\ if (sqlite3_prepare_v2(m_db, stmtSrc, 0, &outVar, NULL) != SQLITE_OK)\ diff --git a/hecl/lib/database/database.pri b/hecl/lib/database/database.pri index 12388991e..3951aa393 100644 --- a/hecl/lib/database/database.pri +++ b/hecl/lib/database/database.pri @@ -7,6 +7,8 @@ HEADERS += \ SOURCES += \ $$PWD/HECLDatabase.cpp \ - $$PWD/sqlite_hecl_mem_vfs.c \ $$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 diff --git a/hecl/lib/database/sqlite_hecl_mem_vfs.c b/hecl/lib/database/sqlite_hecl_mem_vfs.c index 303005973..0dfa53e1d 100644 --- a/hecl/lib/database/sqlite_hecl_mem_vfs.c +++ b/hecl/lib/database/sqlite_hecl_mem_vfs.c @@ -257,10 +257,10 @@ static int memOpen( 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"); - abort(); + fprintf(stderr, "the sqlite hecl mem VFS only supports main-db reading/writing\n"); + return SQLITE_CANTOPEN; } mem_file* p2 = (mem_file*)pFile; memset(p2, 0, sizeof(*p2)); diff --git a/hecl/lib/database/sqlite_hecl_memlba_make.c b/hecl/lib/database/sqlite_hecl_memlba_make.c new file mode 100644 index 000000000..e222c8b55 --- /dev/null +++ b/hecl/lib/database/sqlite_hecl_memlba_make.c @@ -0,0 +1,108 @@ +#include "sqlite_hecl_vfs.h" +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include + +#include + +/* + * 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 ; icachedBlockAges[i] != 0) + ++file->cachedBlockAges[i]; + for (i=0 ; icachedBlockAges[i] == 0) + { + file->cachedBlockAges[i] = 1; + return i; + } + for (i=0 ; icachedBlockAges[i] == BLOCK_SLOTS+1) + { + file->cachedBlockAges[i] = 1; + return i; + } + /* Shouldn't happen (fallback) */ + for (i=1 ; icachedBlockAges[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 ; icachedBlockIndices[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 ; icachedBlockBufs[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); +} diff --git a/hecl/lib/database/sqlite_hecl_vfs.h b/hecl/lib/database/sqlite_hecl_vfs.h index 85e9b24c6..481a9fbc9 100644 --- a/hecl/lib/database/sqlite_hecl_vfs.h +++ b/hecl/lib/database/sqlite_hecl_vfs.h @@ -5,10 +5,14 @@ extern "C" { #endif +#include #include +#include + typedef void(*TCloseCallback)(void* buf, size_t bufLen, 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 }