Skip to content

Commit

Permalink
Add NDBVolume wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
shermp committed Apr 15, 2024
1 parent 93520ae commit ad05b3b
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 19 deletions.
62 changes: 45 additions & 17 deletions src/ndb/NDBMetadata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,44 @@
#include "util.h"
#include "NDBMetadata.h"

/* Volume/Content objects appear to be only 8 bytes. They
hold a pointer to a much larger ContentPrivate/VolumePrivate
object (VolumePrivate is at least 400 bytes).
Setting 16 bytes just to be safe here. */
#define VOLUME_SIZE 16

#define NDB_RESOLVE_ATTR(attr, required) if (!resolve_attr(attr, "ATTRIBUTE_" #attr, required)) return

namespace NDB {
void (*Volume__Volume)(Volume* _this);

NDBVolume::NDBVolume() {
initResult = SymbolError;
resolveSymbolRTLD("_ZTV6Volume", nh_symoutptr(Volume_vtable));
NDB_ASSERT_RET(Volume_vtable, "Volume vtable not found");
resolveSymbolRTLD("_ZTV7Content", nh_symoutptr(Content_vtable));
NDB_ASSERT_RET(Content_vtable, "Content vtable not found");
initResult = InitError;
Volume__Volume((Volume*)&vol);
NDB_ASSERT_RET(vol.vptr != nullptr && vol.vol_private != nullptr, "Volume not constructed correctly");
initResult = Ok;
return;
}

/* Volume contains a large heap allocated VolumePrivate member variable that needs to be cleaned up
Thankfully it has a virtual destructor. */
NDBVolume::~NDBVolume() {
// Don't try and call the destructor if we never got a valid object
NDB_ASSERT_RET(initResult == Ok, "Volume was not initialised.");
NDB_ASSERT_RET(vol.vptr != nullptr && vol.vol_private != nullptr, "vptr or VolumePrivate not set on Volume.");

// Shamelessly stolen from NickelMenu
#define vtable_target(x) reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(x)+8)
nh_log("Value of Content vtable: %p", vtable_target(Content_vtable));
nh_log(" Value of Volume vtable: %p", vtable_target(Volume_vtable));
nh_log(" Value of current vptr: %p", vol.vptr);
NDB_ASSERT_RET(vol.vptr == vtable_target(Volume_vtable), "unexpected vtable layout (expected class to start with a pointer to 8 bytes into the vtable)");

vol.vptr->volume_dstor(&vol);
nh_log("Virtual Volume Destructor invoked.");
return;
}



NDBMetadata::~NDBMetadata() {}

Expand Down Expand Up @@ -52,17 +81,17 @@ NDBMetadata::NDBMetadata(QObject* parent) : QObject(parent) {
nh_log("DB name is %s", dbName->toUtf8().constData());

resolveSymbolRTLD("_ZN13VolumeManager7getByIdERK7QStringS2_", nh_symoutptr(symbols.VolumeManager__getById));
resolveSymbolRTLD("_ZN6VolumeC1Ev", nh_symoutptr(symbols.Volume__Volume));
resolveSymbolRTLD("_ZN13VolumeManager7forEachERK7QStringRKSt8functionIFvRK6VolumeEE", nh_symoutptr(symbols.VolumeManager__forEach));
resolveSymbolRTLD("_ZN6VolumeC1Ev", nh_symoutptr(Volume__Volume));
resolveSymbolRTLD("_ZNK6Volume7isValidEv", nh_symoutptr(symbols.Volume__isValid));
resolveSymbolRTLD("_ZNK6Volume11getDbValuesEv", nh_symoutptr(symbols.Volume__getDbValues));
resolveSymbolRTLD("_ZN13VolumeManager7forEachERK7QStringRKSt8functionIFvRK6VolumeEE", nh_symoutptr(symbols.Volume__forEach));
resolveSymbolRTLD("_ZN6Volume12setAttributeERK7QStringRK8QVariant", nh_symoutptr(symbols.Volume__setAttribute));
resolveSymbolRTLD("_ZN6Volume4saveERK6Device", nh_symoutptr(symbols.Volume__save));
if (!symbols.VolumeManager__getById ||
!symbols.Volume__Volume ||
!symbols.VolumeManager__forEach ||
!Volume__Volume ||
!symbols.Volume__getDbValues ||
!symbols.Volume__isValid ||
!symbols.Volume__forEach ||
!symbols.Volume__setAttribute ||
!symbols.Volume__save) {
initResult = SymbolError;
Expand Down Expand Up @@ -106,9 +135,9 @@ Volume* NDBMetadata::getByID(Volume* vol, QString const& id) {
}

QVariantMap NDBMetadata::getMetadata(QString const& cID) {
uint8_t va[VOLUME_SIZE] = {0};
symbols.Volume__Volume(va);
Volume* v = getByID((Volume*)va, cID);
NDBVolume vol;
NDB_ASSERT(QVariantMap(), vol.initResult == Ok, "Unable to construct Volume");
Volume* v = getByID(vol.getVolume(), cID);
return getMetadata(v);
}

Expand All @@ -123,7 +152,7 @@ QVariantMap NDBMetadata::getMetadata(Volume* v) {
QStringList NDBMetadata::getBookList(std::function<bool (Volume*)> filter) {
NDB_DEBUG("calling Volume::forEach()");
QStringList bookList = {};
symbols.Volume__forEach(*dbName, [&](Volume *v) {
symbols.VolumeManager__forEach(*dbName, [&](Volume *v) {
if (volIsValid(v) && filter(v)) {
QVariantMap values = getMetadata(v);
QString cID = values[CONTENT_ID].toString();
Expand Down Expand Up @@ -155,9 +184,8 @@ QStringList NDBMetadata::getBookListSideloaded() {
}

Result NDBMetadata::setMetadata(QString const& cID, QVariantMap md) {
uint8_t va[VOLUME_SIZE] = {0};
symbols.Volume__Volume(va);
Volume* v = getByID((Volume*)va, cID);
NDBVolume vol;
Volume* v = getByID(vol.getVolume(), cID);
NDB_ASSERT(NullError, v, "Error getting Volume for %s", cID.toUtf8().constData());
NDB_ASSERT(VolumeError, volIsValid(v), "Volume is not valid for %s", cID.toUtf8().constData());
for (auto i = md.constBegin(); i != md.constEnd(); ++i) {
Expand Down
32 changes: 30 additions & 2 deletions src/ndb/NDBMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,37 @@ typedef void Volume; // Inherits Content
typedef QObject VolumeManager; // The VolumeManager is a QObject though
typedef void Device;

/* Volume/Content objects appear to be only 8 bytes. They
hold a pointer to a much larger ContentPrivate/VolumePrivate
object (VolumePrivate is at least 400 bytes).
Setting 16 bytes just to be safe here. */
#define VOLUME_SIZE 16

namespace NDB {

typedef void(*dstor_ptr_t)(void*);

struct VolVtable {
dstor_ptr_t volume_dstor;
};

class NDBVolume {
public:
enum Result initResult;
Volume* getVolume() { return (Volume*)&vol; }

NDBVolume();
~NDBVolume();
private:
// Volume contains a vptr and a VolumePrivate ptr
struct {
VolVtable* vptr = nullptr;
void* vol_private = nullptr;
} vol;
void* Volume_vtable;
void* Content_vtable;
};

class NDBMetadata : public QObject {
Q_OBJECT

Expand Down Expand Up @@ -48,8 +77,7 @@ class NDBMetadata : public QObject {
// Getting Volume's
VolumeManager* (*VolumeManager__sharedInstance)();
Volume* (*VolumeManager__getById)(Volume* vol, QString const& id, QString const& dbName);
void (*Volume__Volume)(Volume* _this);
void (*Volume__forEach)(QString const& dbName, std::function<void(Volume /*const&*/ *v)> f);
void (*VolumeManager__forEach)(QString const& dbName, std::function<void(Volume /*const&*/ *v)> f);
int (*Volume__isValid)(Volume* _this);
QVariantMap (*Volume__getDbValues)(Volume* volume);
int (*Volume__save)(Volume* _this, Device* device);
Expand Down
1 change: 1 addition & 0 deletions src/ndb/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace NDB {
#endif

#define NDB_ASSERT(ret, cond, fmt, ...) if (!(cond)) { nh_log(fmt, ##__VA_ARGS__); return (ret); }
#define NDB_ASSERT_RET(cond, fmt, ...) if (!(cond)) { nh_log(fmt, ##__VA_ARGS__); return; }
#define NDB_ASSERT_RES(res, func) (res) = (func); if ((res) != Ok) { return (res); }

// like NDB_ASSERT, but sends an appropriate d-bus error on the bus before returning
Expand Down

0 comments on commit ad05b3b

Please sign in to comment.