433 lines
8.3 KiB
C++
433 lines
8.3 KiB
C++
|
#include "idm.h"
|
||
|
|
||
|
const QByteArray Idm::TAG = "IDM";
|
||
|
const int Idm::MAX_MAJOR = 1;
|
||
|
const int Idm::MAX_MINOR = 0;
|
||
|
int Idm::DEFAULT_INT_SIZE = 3;
|
||
|
int Idm::DEFAULT_FLAGS = 1; // FIXED_KEY_LEN
|
||
|
int Idm::DEFAULT_KEY_LEN = 1;
|
||
|
int Idm::CURRENT_MAJOR = Idm::MAX_MAJOR;
|
||
|
int Idm::CURRENT_MINOR = Idm::MAX_MINOR;
|
||
|
|
||
|
Idm::Idm(const QByteArray &data, QObject *parent) : QObject(parent)
|
||
|
{
|
||
|
buffPtr = data;
|
||
|
|
||
|
init();
|
||
|
}
|
||
|
|
||
|
Idm::Idm(QObject *parent) : QObject(parent)
|
||
|
{
|
||
|
init();
|
||
|
}
|
||
|
|
||
|
void Idm::init()
|
||
|
{
|
||
|
header = 0;
|
||
|
intSize = DEFAULT_INT_SIZE;
|
||
|
keyLen = DEFAULT_KEY_LEN;
|
||
|
flags = DEFAULT_FLAGS;
|
||
|
}
|
||
|
|
||
|
void Idm::loadData(const QByteArray &data)
|
||
|
{
|
||
|
op(RELOAD, data);
|
||
|
}
|
||
|
|
||
|
QByteArray &Idm::getBuff()
|
||
|
{
|
||
|
op(GET_BUFF, QByteArray(), QByteArray(), new QByteArray());
|
||
|
|
||
|
return buffPtr;
|
||
|
}
|
||
|
|
||
|
bool Idm::rdHeader()
|
||
|
{
|
||
|
return rdExHeader(buffPtr);
|
||
|
}
|
||
|
|
||
|
bool Idm::rdExHeader(const QByteArray &data)
|
||
|
{
|
||
|
bool ret;
|
||
|
|
||
|
op(RD_HEADER, data, QByteArray(), 0, 0, 0, &ret);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool Idm::rdExHeader(const QByteArray &data, int &major, int &minor, int &intSz, int &flgs, int &keyLen)
|
||
|
{
|
||
|
bool ret = false;
|
||
|
|
||
|
if (data.startsWith(TAG))
|
||
|
{
|
||
|
int pos = TAG.size();
|
||
|
|
||
|
major = rdInt(data.mid(pos++, 1));
|
||
|
minor = rdInt(data.mid(pos++, 1));
|
||
|
intSz = rdInt(data.mid(pos++, 1));
|
||
|
keyLen = rdInt(data.mid(pos++, 1));
|
||
|
flgs = rdInt(data.mid(pos, 4));
|
||
|
|
||
|
if ((major <= MAX_MAJOR) && (minor <= MAX_MINOR))
|
||
|
{
|
||
|
ret = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool Idm::verifyExHeader(const QByteArray &data, int major, int minor)
|
||
|
{
|
||
|
bool ret = false;
|
||
|
|
||
|
if (data.startsWith(TAG) && (data.size() == 11))
|
||
|
{
|
||
|
int pos = TAG.size();
|
||
|
int ma = rdInt(data.mid(pos++, 1));
|
||
|
int mi = rdInt(data.mid(pos++, 1));
|
||
|
|
||
|
ret = ((ma <= major) && (mi <= minor));
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
QByteArray Idm::buildHeader(int major, int minor, int intSz, int flgs, int keyLen)
|
||
|
{
|
||
|
QByteArray ret = TAG;
|
||
|
|
||
|
ret.append(wrInt(major, 1));
|
||
|
ret.append(wrInt(minor, 1));
|
||
|
ret.append(wrInt(intSz, 1));
|
||
|
ret.append(wrInt(keyLen, 1));
|
||
|
ret.append(wrInt(flgs, 4));
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void Idm::setKeyLen(int len)
|
||
|
{
|
||
|
op(SET_KEY_LEN, QByteArray(), QByteArray(), 0, len);
|
||
|
}
|
||
|
|
||
|
void Idm::setFlags(int flgs)
|
||
|
{
|
||
|
op(SET_FLAGS, QByteArray(), QByteArray(), 0, flgs);
|
||
|
}
|
||
|
|
||
|
void Idm::wrHeader()
|
||
|
{
|
||
|
op(WR_HEADER);
|
||
|
}
|
||
|
|
||
|
void Idm::setIntSize(int bytes)
|
||
|
{
|
||
|
op(SET_INT_SIZE, QByteArray(), QByteArray(), 0, bytes);
|
||
|
}
|
||
|
|
||
|
void Idm::setVersion(int major, int minor)
|
||
|
{
|
||
|
op(SET_VERSION, QByteArray(), QByteArray(), 0, major, minor);
|
||
|
}
|
||
|
|
||
|
QByteArray Idm::rdData(int addr, int len, bool *ret)
|
||
|
{
|
||
|
bool ok = false;
|
||
|
|
||
|
if ((addr < buffPtr.size()) && (addr >= 0))
|
||
|
{
|
||
|
if ((len + addr) <= buffPtr.size())
|
||
|
{
|
||
|
ok = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ret) *ret = ok;
|
||
|
|
||
|
if (ok)
|
||
|
{
|
||
|
return QByteArray::fromRawData(buffPtr.data() + addr, len);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return QByteArray();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool Idm::findKey(int &addr, int &dataLen, const QByteArray &key)
|
||
|
{
|
||
|
bool ok = true;
|
||
|
bool found = false;
|
||
|
|
||
|
while(addr < buffPtr.size() && ok)
|
||
|
{
|
||
|
int keySize;
|
||
|
|
||
|
if (flags & FIXED_KEY_LEN)
|
||
|
{
|
||
|
keySize = keyLen;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
keySize = rdInt(rdData(addr, intSize, &ok));
|
||
|
|
||
|
addr += intSize;
|
||
|
}
|
||
|
|
||
|
if (ok)
|
||
|
{
|
||
|
if (key == rdData(addr, keySize, &ok))
|
||
|
{
|
||
|
found = true;
|
||
|
}
|
||
|
|
||
|
addr += keySize;
|
||
|
|
||
|
if (ok)
|
||
|
{
|
||
|
dataLen = rdInt(rdData(addr, intSize, &ok));
|
||
|
|
||
|
addr += intSize;
|
||
|
|
||
|
if (found && ok)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
addr += dataLen;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
QByteArray Idm::value(const QByteArray &key)
|
||
|
{
|
||
|
QByteArray ret;
|
||
|
|
||
|
op(RD_VALUE, key, QByteArray(), &ret);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
QByteArray Idm::value(quint64 key)
|
||
|
{
|
||
|
int keySize;
|
||
|
|
||
|
if (flags & FIXED_KEY_LEN) keySize = keyLen;
|
||
|
else keySize = intSize;
|
||
|
|
||
|
return value(wrInt(key, keySize));
|
||
|
}
|
||
|
|
||
|
quint64 Idm::intValue(const QByteArray &key)
|
||
|
{
|
||
|
return rdInt(value(key));
|
||
|
}
|
||
|
|
||
|
quint64 Idm::intValue(quint64 key)
|
||
|
{
|
||
|
return rdInt(value(key));
|
||
|
}
|
||
|
|
||
|
bool Idm::remove(const QByteArray &key)
|
||
|
{
|
||
|
bool ret;
|
||
|
|
||
|
op(RM_VALUE, key, QByteArray(), 0, 0, 0, &ret);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool Idm::remove(quint64 key)
|
||
|
{
|
||
|
int keySize;
|
||
|
|
||
|
if (flags & FIXED_KEY_LEN) keySize = keyLen;
|
||
|
else keySize = intSize;
|
||
|
|
||
|
return remove(wrInt(key, keySize));
|
||
|
}
|
||
|
|
||
|
bool Idm::insert(const QByteArray &key, const QByteArray &data)
|
||
|
{
|
||
|
bool ret;
|
||
|
|
||
|
op(WR_VALUE, key, data, 0, 0, 0, &ret);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool Idm::insert(quint64 key, quint64 num)
|
||
|
{
|
||
|
int keySize;
|
||
|
|
||
|
if (flags & FIXED_KEY_LEN) keySize = keyLen;
|
||
|
else keySize = intSize;
|
||
|
|
||
|
return insert(wrInt(key, keySize), wrInt(num, intSize));
|
||
|
}
|
||
|
|
||
|
bool Idm::insert(quint64 key, const QByteArray &data)
|
||
|
{
|
||
|
int keySize;
|
||
|
|
||
|
if (flags & FIXED_KEY_LEN) keySize = keyLen;
|
||
|
else keySize = intSize;
|
||
|
|
||
|
return insert(wrInt(key, keySize), data);
|
||
|
}
|
||
|
|
||
|
void Idm::op(Operation opr,
|
||
|
const QByteArray &inA,
|
||
|
const QByteArray &inB,
|
||
|
QByteArray *out,
|
||
|
int intA,
|
||
|
int intB,
|
||
|
bool *ok)
|
||
|
{
|
||
|
QMutex m;
|
||
|
|
||
|
m.lock();
|
||
|
|
||
|
switch(opr)
|
||
|
{
|
||
|
case SET_KEY_LEN:
|
||
|
{
|
||
|
keyLen = intA; break;
|
||
|
}
|
||
|
case SET_FLAGS:
|
||
|
{
|
||
|
flags = intA; break;
|
||
|
}
|
||
|
case GET_BUFF:
|
||
|
{
|
||
|
out = &buffPtr; break;
|
||
|
}
|
||
|
case RELOAD:
|
||
|
{
|
||
|
buffPtr = inA; break;
|
||
|
}
|
||
|
case SET_INT_SIZE:
|
||
|
{
|
||
|
intSize = intA; break;
|
||
|
}
|
||
|
case SET_VERSION:
|
||
|
{
|
||
|
CURRENT_MAJOR = intA;
|
||
|
CURRENT_MINOR = intB;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case WR_HEADER:
|
||
|
{
|
||
|
if (buffPtr.startsWith(TAG))
|
||
|
{
|
||
|
int pos = TAG.size();
|
||
|
|
||
|
buffPtr.replace(pos++, 1, wrInt(CURRENT_MAJOR, 1));
|
||
|
buffPtr.replace(pos++, 1, wrInt(CURRENT_MINOR, 1));
|
||
|
buffPtr.replace(pos++, 1, wrInt(intSize, 1));
|
||
|
buffPtr.replace(pos++, 1, wrInt(keyLen, 1));
|
||
|
buffPtr.replace(pos++, 4, wrInt(flags, 4));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
buffPtr.insert(0, wrInt(flags, 4));
|
||
|
buffPtr.insert(0, wrInt(keyLen, 1));
|
||
|
buffPtr.insert(0, wrInt(intSize, 1));
|
||
|
buffPtr.insert(0, wrInt(CURRENT_MINOR, 1));
|
||
|
buffPtr.insert(0, wrInt(CURRENT_MAJOR, 1));
|
||
|
buffPtr.insert(0, TAG);
|
||
|
}
|
||
|
|
||
|
header = 8 + TAG.size();
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case RD_HEADER:
|
||
|
{
|
||
|
*ok = rdExHeader(inA, CURRENT_MAJOR, CURRENT_MINOR, intSize, flags, keyLen);
|
||
|
|
||
|
if (*ok) header = 8 + TAG.size();
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case RD_VALUE:
|
||
|
{
|
||
|
int pos = header;
|
||
|
int len = 0;
|
||
|
|
||
|
if (findKey(pos, len, inA))
|
||
|
{
|
||
|
out->clear();
|
||
|
out->append(buffPtr.mid(pos, len));
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case RM_VALUE:
|
||
|
{
|
||
|
int pos = header;
|
||
|
int len = 0;
|
||
|
|
||
|
*ok = false;
|
||
|
|
||
|
if (findKey(pos, len, inA))
|
||
|
{
|
||
|
if (flags & FIXED_KEY_LEN)
|
||
|
{
|
||
|
pos -= keyLen + intSize;
|
||
|
len += keyLen + intSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pos -= inA.size() + (intSize * 2);
|
||
|
len += inA.size() + (intSize * 2);
|
||
|
}
|
||
|
|
||
|
buffPtr.remove(pos, len);
|
||
|
|
||
|
*ok = true;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case WR_VALUE:
|
||
|
{
|
||
|
*ok = false;
|
||
|
|
||
|
remove(inA);
|
||
|
|
||
|
if (flags & FIXED_KEY_LEN)
|
||
|
{
|
||
|
if (inA.size() == keyLen)
|
||
|
{
|
||
|
buffPtr.append(inA + wrInt(inB.size(), intSize) + inB);
|
||
|
|
||
|
*ok = true;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!inA.isEmpty())
|
||
|
{
|
||
|
buffPtr.append(wrInt(inA.size(), intSize) + inA);
|
||
|
buffPtr.append(wrInt(inB.size(), intSize) + inB);
|
||
|
|
||
|
*ok = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m.unlock();
|
||
|
}
|