/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "filesystem/data_store.h" #include "rand/rand.h" #include "memory/nauto_ptr.h" using namespace GS; using namespace GS::IO; //------------------------------------------------------------------------------ DataStore::Entry *DataStore::GetEntry(const String &id) const { ListForeachPtr(Entry *, e, entries) if (e->id == id) return e; return NULL; } String DataStore::GetNewId() { for ( ; ; ++id_seed) { String id = String::Format("store_%012d", id_seed); if (GetEntry(id) == NULL) return id; } return String(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ size_t DataStore::GetEntrySize(const String &id) const { if (Entry *e = GetEntry(id)) return e->size; return 0; } size_t DataStore::GetStoreSize() const { size_t size = 0; ListForeachPtr(Entry *, e, entries) size += e->size; return size; } size_t DataStore::GetFreeStore() const { return limit - GetStoreSize(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ String DataStore::Reserve(size_t size) { Threading::MutexLock lock(&mutex); if (limit > 0) // enforce size limit { size_t store_size = GetStoreSize(); if (size > (limit - store_size)) return String(); // store is full } // Reserve a new entry. Entry *entry = new Entry; entry->id = GetNewId(); entry->size = size; entries.Add(entry); return entry->id; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool DataStore::Store(const String &id, const void *data, size_t size, const char *user) { Threading::MutexLock lock(&mutex); Entry *entry = GetEntry(id); if ((entry == NULL) || (entry->size != size)) return false; // invalid id/store size lock.Unlock(); entry->user = user; AutoPtr h(io->Open(id, ModeWrite)); return h.IsValid() && (h->Write(data, size) == size); } bool DataStore::Free(const String &id) { Threading::MutexLock lock(&mutex); Entry *entry = GetEntry(id); if (entry == NULL) return false; // invalid id if (!io->Delete(id)) return false; return entries.Remove(entry); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Store format // // 18 bytes - id // 4 bytes - size in bytes // ----------------------------- bool DataStore::Load(const char *path) { AutoPtr h(io->Open(path)); if (h.IsNull()) return true; // nothing to restore entries.Clear(); char id[18]; while (!h->IsEOF()) { if (h->Read((void *)id, 18) != 18) return false; Entry *e = new Entry; e->id.Set(id, id + 18); e->size = h->Read (); uint user_data_size = h->Read (); if (!e->user.Allocate(user_data_size)) return false; h->Read((void *)e->user.c_str(), user_data_size); entries.Add(e); } return true; } bool DataStore::Save(const char *path) { AutoPtr h(io->Open(path, ModeWrite)); if (h.IsNull()) return false; ListForeachPtr(Entry *, e, entries) { h->Write(e->id.c_str(), 18); h->Write(&e->size, 4); uint user_data_size = e->user.Len(); h->Write(user_data_size); if (user_data_size > 0) h->Write(e->user.c_str(), user_data_size); } return true; } //------------------------------------------------------------------------------