#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(); }