mirror of https://github.com/AxioDL/metaforce.git
implemented lba VFS
This commit is contained in:
parent
f02aa1ca8f
commit
db0ce36b90
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)\
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue