2014-08-04 14:38:42 +04:00
|
|
|
// vim: set ts=4 sw=4 tw=99 noet:
|
|
|
|
//
|
|
|
|
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
|
|
// Copyright (C) The AMX Mod X Development Team.
|
|
|
|
//
|
|
|
|
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
|
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
|
|
// https://alliedmods.net/amxmodx-license
|
|
|
|
|
|
|
|
//
|
|
|
|
// NVault Module
|
|
|
|
//
|
|
|
|
|
2006-06-04 11:49:07 +04:00
|
|
|
#include <stdio.h>
|
2006-04-07 14:25:45 +04:00
|
|
|
#include "amxxmodule.h"
|
2005-07-31 10:07:48 +04:00
|
|
|
#include "NVault.h"
|
|
|
|
#include "Binary.h"
|
2005-08-02 13:48:06 +04:00
|
|
|
#include "CString.h"
|
2005-07-31 10:07:48 +04:00
|
|
|
|
2006-08-21 01:23:38 +04:00
|
|
|
/**
|
|
|
|
* :TODO: This beast calls strcpy()/new() way too much by creating new strings on the stack.
|
|
|
|
* That's easily remedied and it should be fixed?
|
|
|
|
* ---bail
|
|
|
|
*/
|
|
|
|
|
2005-08-02 13:48:06 +04:00
|
|
|
template <>
|
|
|
|
int HashFunction<String>(const String & k)
|
2005-07-31 10:07:48 +04:00
|
|
|
{
|
|
|
|
unsigned long hash = 5381;
|
|
|
|
const char *str = k.c_str();
|
|
|
|
char c;
|
2006-08-18 23:08:51 +04:00
|
|
|
while ((c = *str++))
|
|
|
|
{
|
|
|
|
hash = ((hash << 5) + hash) + c; // hash*33 + c
|
|
|
|
}
|
2005-07-31 10:07:48 +04:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2005-08-02 13:48:06 +04:00
|
|
|
template <>
|
2005-09-18 06:59:36 +04:00
|
|
|
int Compare<String>(const String & k1, const String & k2)
|
2005-07-31 10:07:48 +04:00
|
|
|
{
|
2005-09-18 06:59:36 +04:00
|
|
|
return strcmp(k1.c_str(),k2.c_str());
|
2005-07-31 10:07:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NVault::NVault(const char *file)
|
|
|
|
{
|
|
|
|
m_File.assign(file);
|
|
|
|
m_Journal = NULL;
|
|
|
|
m_Open = false;
|
2006-08-19 02:46:07 +04:00
|
|
|
|
|
|
|
FILE *fp = fopen(m_File.c_str(), "rb");
|
|
|
|
if (!fp)
|
|
|
|
{
|
|
|
|
fp = fopen(m_File.c_str(), "wb");
|
|
|
|
if (!fp)
|
|
|
|
{
|
2008-03-04 22:06:39 +03:00
|
|
|
this->m_Valid = false;
|
|
|
|
return;
|
2006-08-19 02:46:07 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
this->m_Valid = true;
|
2006-08-19 02:46:07 +04:00
|
|
|
fclose(fp);
|
2005-07-31 10:07:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NVault::~NVault()
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
VaultError NVault::_ReadFromFile()
|
|
|
|
{
|
|
|
|
FILE *fp = fopen(m_File.c_str(), "rb");
|
|
|
|
|
|
|
|
if (!fp)
|
2006-08-19 02:46:07 +04:00
|
|
|
{
|
2005-07-31 10:07:48 +04:00
|
|
|
return Vault_NoFile;
|
2006-08-19 02:46:07 +04:00
|
|
|
}
|
2005-07-31 10:07:48 +04:00
|
|
|
//this is a little more optimized than the other version in the journal <_<
|
|
|
|
//I could optimize this more by embedding the position in the hash table but...
|
|
|
|
// the hash function can be changed. this could be fixed by storing a string and its
|
|
|
|
// resulting hash, and the entries could be ignored therein, but not right now.
|
|
|
|
//Also the string class could have embedded binary reading (like it does for text files)
|
|
|
|
BinaryReader br(fp);
|
|
|
|
|
|
|
|
uint8_t oldkeylen=0;
|
|
|
|
uint16_t oldvallen=0;
|
|
|
|
uint8_t keylen;
|
|
|
|
uint16_t vallen;
|
|
|
|
time_t stamp;
|
|
|
|
char *key = NULL;
|
|
|
|
char *val = NULL;
|
|
|
|
String sKey;
|
|
|
|
String sVal;
|
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
// try
|
|
|
|
// {
|
|
|
|
uint32_t magic;
|
|
|
|
if (!br.ReadUInt32(magic)) goto fail;
|
|
|
|
|
2005-07-31 10:07:48 +04:00
|
|
|
if (magic != VAULT_MAGIC)
|
|
|
|
return Vault_BadFile;
|
2008-03-04 22:06:39 +03:00
|
|
|
|
|
|
|
|
|
|
|
uint16_t version;
|
|
|
|
if (!br.ReadUInt16(version)) goto fail;
|
|
|
|
|
2005-07-31 10:07:48 +04:00
|
|
|
if (version != VAULT_VERSION)
|
|
|
|
return Vault_OldFile;
|
2008-03-04 22:06:39 +03:00
|
|
|
|
|
|
|
int32_t entries;
|
|
|
|
|
|
|
|
if (!br.ReadInt32(entries)) goto fail;
|
|
|
|
|
|
|
|
|
|
|
|
int32_t temp;
|
2005-07-31 10:07:48 +04:00
|
|
|
for (int32_t i=0; i<entries; i++)
|
|
|
|
{
|
2008-03-04 22:06:39 +03:00
|
|
|
if (!br.ReadInt32(temp)) goto fail;
|
|
|
|
|
|
|
|
stamp = static_cast<time_t>(temp);
|
|
|
|
|
|
|
|
if (!br.ReadUInt8(keylen)) goto fail;
|
|
|
|
if (!br.ReadUInt16(vallen)) goto fail;
|
|
|
|
|
2005-07-31 10:07:48 +04:00
|
|
|
if (keylen > oldkeylen)
|
|
|
|
{
|
|
|
|
if (key)
|
|
|
|
delete [] key;
|
|
|
|
key = new char[keylen + 1];
|
|
|
|
oldkeylen = keylen;
|
|
|
|
}
|
|
|
|
if (vallen > oldvallen)
|
|
|
|
{
|
|
|
|
if (val)
|
|
|
|
delete [] val;
|
|
|
|
val = new char[vallen + 1];
|
|
|
|
oldvallen = vallen;
|
|
|
|
}
|
2008-03-04 22:06:39 +03:00
|
|
|
|
|
|
|
if (!br.ReadChars(key, keylen)) goto fail;
|
|
|
|
if (!br.ReadChars(val, vallen)) goto fail;
|
|
|
|
|
2005-07-31 10:07:48 +04:00
|
|
|
key[keylen] = '\0';
|
|
|
|
val[vallen] = '\0';
|
|
|
|
sKey.assign(key);
|
|
|
|
sVal.assign(val);
|
|
|
|
m_Hash.Insert(sKey, sVal, stamp);
|
|
|
|
}
|
2008-03-04 22:06:39 +03:00
|
|
|
|
|
|
|
// } catch (...) {
|
|
|
|
|
|
|
|
goto success;
|
|
|
|
fail:
|
|
|
|
if (key)
|
|
|
|
{
|
|
|
|
delete [] key;
|
|
|
|
key = NULL;
|
|
|
|
}
|
|
|
|
if (val)
|
|
|
|
{
|
|
|
|
delete [] val;
|
|
|
|
val = NULL;
|
2005-07-31 10:07:48 +04:00
|
|
|
}
|
2008-03-04 22:06:39 +03:00
|
|
|
fclose(fp);
|
|
|
|
return Vault_Read;
|
|
|
|
// }
|
2005-07-31 10:07:48 +04:00
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
success:
|
2005-07-31 10:07:48 +04:00
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return Vault_Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NVault::_SaveToFile()
|
|
|
|
{
|
|
|
|
FILE *fp = fopen(m_File.c_str(), "wb");
|
|
|
|
|
|
|
|
if (!fp)
|
2006-08-19 02:46:07 +04:00
|
|
|
{
|
2005-07-31 10:07:48 +04:00
|
|
|
return false;
|
2006-08-19 02:46:07 +04:00
|
|
|
}
|
2005-07-31 10:07:48 +04:00
|
|
|
|
|
|
|
BinaryWriter bw(fp);
|
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
// try
|
|
|
|
// {
|
|
|
|
uint32_t magic = VAULT_MAGIC;
|
|
|
|
uint16_t version = VAULT_VERSION;
|
2005-07-31 10:07:48 +04:00
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
time_t stamp;
|
|
|
|
String key;
|
|
|
|
String val;
|
2005-07-31 10:07:48 +04:00
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
THash<String,String>::iterator iter = m_Hash.begin();
|
|
|
|
|
|
|
|
if (!bw.WriteUInt32(magic)) goto fail;
|
|
|
|
if (!bw.WriteUInt16(version)) goto fail;
|
|
|
|
|
|
|
|
if (!bw.WriteUInt32( m_Hash.Size() )) goto fail;
|
2005-07-31 10:07:48 +04:00
|
|
|
|
2008-03-04 22:06:39 +03:00
|
|
|
while (iter != m_Hash.end())
|
|
|
|
{
|
|
|
|
key = (*iter).key;
|
|
|
|
val = (*iter).val;
|
|
|
|
stamp = (*iter).stamp;
|
|
|
|
|
|
|
|
if (!bw.WriteInt32(static_cast<int32_t>(stamp))) goto fail;;
|
|
|
|
if (!bw.WriteUInt8( key.size() )) goto fail;
|
|
|
|
if (!bw.WriteUInt16( val.size() )) goto fail;
|
|
|
|
if (!bw.WriteChars( key.c_str(), key.size() )) goto fail;
|
|
|
|
if (!bw.WriteChars( val.c_str(), val.size() )) goto fail;
|
|
|
|
iter++;
|
2005-07-31 10:07:48 +04:00
|
|
|
}
|
2008-03-04 22:06:39 +03:00
|
|
|
|
|
|
|
goto success;
|
|
|
|
// } catch (...) {
|
|
|
|
|
|
|
|
fail:
|
|
|
|
fclose(fp);
|
|
|
|
return false;
|
|
|
|
// }
|
|
|
|
success:
|
2005-07-31 10:07:48 +04:00
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-08-01 23:56:54 +04:00
|
|
|
const char *NVault::GetValue(const char *key)
|
|
|
|
{
|
|
|
|
String sKey(key);
|
|
|
|
if (!m_Hash.Exists(sKey))
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
} else {
|
|
|
|
return m_Hash.Retrieve(sKey).c_str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-31 10:07:48 +04:00
|
|
|
bool NVault::Open()
|
|
|
|
{
|
|
|
|
_ReadFromFile();
|
|
|
|
|
|
|
|
char *journal_name = new char[m_File.size() + 10];
|
|
|
|
strcpy(journal_name, m_File.c_str());
|
|
|
|
|
|
|
|
char *pos = strstr(journal_name, ".vault");
|
|
|
|
if (pos)
|
|
|
|
{
|
|
|
|
strcpy(pos, ".journal");
|
|
|
|
} else {
|
|
|
|
strcat(journal_name, ".journal");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Journal = new Journal(journal_name);
|
|
|
|
delete [] journal_name;
|
|
|
|
|
|
|
|
m_Journal->Replay(&m_Hash);
|
|
|
|
m_Journal->Erase();
|
2006-08-19 02:46:07 +04:00
|
|
|
if (!m_Journal->Begin())
|
|
|
|
{
|
|
|
|
delete m_Journal;
|
|
|
|
m_Journal = NULL;
|
|
|
|
}
|
2005-07-31 10:07:48 +04:00
|
|
|
|
|
|
|
m_Open = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NVault::Close()
|
|
|
|
{
|
|
|
|
if (!m_Open)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
_SaveToFile();
|
2013-07-02 12:20:21 +04:00
|
|
|
|
|
|
|
if (m_Journal)
|
|
|
|
{
|
|
|
|
m_Journal->End();
|
|
|
|
m_Journal->Erase();
|
|
|
|
}
|
|
|
|
|
2005-08-01 23:56:54 +04:00
|
|
|
m_Open = false;
|
2005-07-31 10:07:48 +04:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NVault::SetValue(const char *key, const char *val)
|
|
|
|
{
|
|
|
|
if (m_Journal)
|
|
|
|
m_Journal->Write_Insert(key, val, time(NULL));
|
|
|
|
String sKey;
|
|
|
|
String sVal;
|
|
|
|
sKey.assign(key);
|
|
|
|
sVal.assign(val);
|
|
|
|
m_Hash.Insert(sKey, sVal);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NVault::SetValue(const char *key, const char *val, time_t stamp)
|
|
|
|
{
|
|
|
|
if (m_Journal)
|
|
|
|
m_Journal->Write_Insert(key, val, stamp);
|
|
|
|
String sKey;
|
|
|
|
String sVal;
|
|
|
|
sKey.assign(key);
|
|
|
|
sVal.assign(val);
|
|
|
|
m_Hash.Insert(sKey, sVal, stamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NVault::Remove(const char *key)
|
|
|
|
{
|
|
|
|
if (m_Journal)
|
|
|
|
m_Journal->Write_Remove(key);
|
|
|
|
String sKey(key);
|
|
|
|
m_Hash.Remove(sKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NVault::Clear()
|
|
|
|
{
|
|
|
|
if (m_Journal)
|
|
|
|
m_Journal->Write_Clear();
|
|
|
|
m_Hash.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t NVault::Items()
|
|
|
|
{
|
|
|
|
return m_Hash.Size();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t NVault::Prune(time_t start, time_t end)
|
|
|
|
{
|
|
|
|
if (m_Journal)
|
|
|
|
m_Journal->Write_Prune(start, end);
|
|
|
|
return m_Hash.Prune(start, end);
|
|
|
|
}
|
|
|
|
|
2006-08-21 01:23:38 +04:00
|
|
|
void NVault::Touch(const char *key, time_t stamp)
|
|
|
|
{
|
|
|
|
String sKey(key);
|
|
|
|
|
|
|
|
if (!m_Hash.Exists(sKey))
|
|
|
|
{
|
|
|
|
SetValue(key, "", time(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Hash.Touch(key, stamp);
|
|
|
|
}
|
|
|
|
|
2005-07-31 10:07:48 +04:00
|
|
|
bool NVault::GetValue(const char *key, time_t &stamp, char buffer[], size_t len)
|
|
|
|
{
|
|
|
|
String sKey(key);
|
|
|
|
if (!m_Hash.Exists(sKey))
|
|
|
|
{
|
|
|
|
buffer[0] = '\0';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t st;
|
|
|
|
String sVal;
|
|
|
|
|
|
|
|
sVal = m_Hash.Retrieve(sKey, st);
|
|
|
|
stamp = st;
|
2014-08-08 15:22:13 +04:00
|
|
|
UTIL_Format(buffer, len, "%s", sVal.c_str());
|
2005-07-31 10:07:48 +04:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2005-08-01 23:56:54 +04:00
|
|
|
|
|
|
|
IVault *VaultMngr::OpenVault(const char *file)
|
|
|
|
{
|
2006-08-19 02:46:07 +04:00
|
|
|
NVault *pVault;
|
2008-03-04 22:06:39 +03:00
|
|
|
//try
|
|
|
|
//{
|
|
|
|
pVault = new NVault(file);
|
|
|
|
|
|
|
|
// } catch (...) {
|
|
|
|
if (!pVault->isValid())
|
2006-08-19 02:46:07 +04:00
|
|
|
{
|
2008-03-04 22:06:39 +03:00
|
|
|
delete pVault;
|
2006-08-19 02:46:07 +04:00
|
|
|
pVault = NULL;
|
|
|
|
}
|
|
|
|
|
2005-08-01 23:56:54 +04:00
|
|
|
return static_cast<IVault *>(pVault);
|
|
|
|
}
|
2005-08-02 00:54:41 +04:00
|
|
|
|