First commit

This commit is contained in:
MultiMote 2017-05-05 21:00:40 +03:00
commit 35beaf4b73
8 changed files with 900 additions and 0 deletions

3
.gitignore vendored Normal file

@ -0,0 +1,3 @@
*.d
*.o
*.mst

500
MStorage.cpp Normal file

@ -0,0 +1,500 @@
#include "MStorage.h"
///////////////////////////////////////////////////////////////////////
MStorageInt32::MStorageInt32(int32_t val) { this->val = val; }
MStorageDataType MStorageInt32::getType() { return MDT_INT32; }
uint8_t MStorageInt32::getByte() { return val & 0xFF; }
double MStorageInt32::getDouble() { return (double)val; }
int32_t MStorageInt32::getInt() { return val; }
void MStorageInt32::writeData(std::ostream &of) {
of.put((char)getType());
of.write((char*)&val , sizeof(int32_t));
}
void MStorageInt32::readData(std::istream &ifs) {
ifs.read((char*)&val, sizeof(int32_t));
}
uint16_t MStorageInt32::getLength(){
return sizeof(int32_t);
}
///////////////////////////////////////////////////////////////////////
MStorageDouble::MStorageDouble(double val) { this->val = val; }
MStorageDataType MStorageDouble::getType() { return MDT_DOUBLE; }
uint8_t MStorageDouble::getByte() { return ((int32_t)val) & 0xFF; }
double MStorageDouble::getDouble() { return val; }
int32_t MStorageDouble::getInt() { return (int32_t)val; }
void MStorageDouble::writeData(std::ostream &of) {
of.put((char)getType());
of.write((char*)&val , sizeof(double));
}
void MStorageDouble::readData(std::istream &ifs) {
ifs.read((char*)&val, sizeof(double));
}
uint16_t MStorageDouble::getLength(){
return sizeof(double);
}
///////////////////////////////////////////////////////////////////////
MStorageByte::MStorageByte(int8_t val) { this->val = val; }
MStorageDataType MStorageByte::getType() { return MDT_BYTE; }
uint8_t MStorageByte::getByte() { return val; }
double MStorageByte::getDouble() { return (double) val; }
int32_t MStorageByte::getInt() { return (int32_t) val; }
void MStorageByte::writeData(std::ostream &of) {
of.put((char)getType());
of.put((char)val);
}
void MStorageByte::readData(std::istream &ifs) {
ifs.read((char*)&val, 1);
}
uint16_t MStorageByte::getLength(){
return 1;
}
///////////////////////////////////////////////////////////////////////
MStorageString::MStorageString(std::string val) {
this->val = val;
}
MStorageDataType MStorageString::getType() {
return MDT_STRING;
}
std::string MStorageString::getString() {
return val;
}
void MStorageString::writeData(std::ostream &of) {
of.put((char)getType());
uint16_t slen = val.size();
of.write((char*)&slen, sizeof(uint16_t));
for(size_t pos = 0; pos < slen; ++pos) {
of << val.at(pos);
}
}
void MStorageString::readData(std::istream &ifs) {
uint16_t slen;
ifs.read((char*)&slen, sizeof(uint16_t));
char* str = new char[slen];
ifs.read(str, slen);
val = std::string(str, slen);
delete[] str;
}
uint16_t MStorageString::getLength(){
return val.size() + sizeof(uint16_t);
}
///////////////////////////////////////////////////////////////////////
MStorageInt32Array::MStorageInt32Array(int32_t *data, uint16_t len){
if(!data || len == 0){
val_len = 0;
val = NULL;
return;
}
val_len = len;
val = new int32_t[val_len];
memcpy(val, data, sizeof(uint32_t) * val_len);
}
MStorageInt32Array::~MStorageInt32Array(){
delete[] val;
}
MStorageDataType MStorageInt32Array::getType(){
return MDT_INT32_ARRAY;
}
int32_t *MStorageInt32Array::getIntArray(){
return val;
}
uint16_t MStorageInt32Array::getLength(){
return sizeof(int32_t) * val_len + sizeof(uint16_t);
}
uint16_t MStorageInt32Array::getArrayLength(){
return val_len;
}
void MStorageInt32Array::writeData(std::ostream &of){
of.put((char)getType());
of.write((char*)&val_len, sizeof(uint16_t));
for(size_t pos = 0; pos < val_len; ++pos) {
of.write((char*)&val[pos] , sizeof(int32_t));
}
}
void MStorageInt32Array::readData(std::istream &ifs){
if(val)
delete[] val;
ifs.read((char*)&val_len, sizeof(uint16_t));
val = new int32_t[val_len];
ifs.read((char*)val, sizeof(int32_t) * val_len);
}
///////////////////////////////////////////////////////////////////////
MStorage::MStorage() {
}
MStorage::~MStorage() {
clear();
}
int8_t MStorage::writeToFile(std::string fname) {
std::ofstream of;
of.open(fname.c_str(), std::ios::binary | std::ios::out);
if(!of.is_open()) {
fprintf(stderr, "MStorage::%s(): Unable to open %s for writing!\n", __FUNCTION__, fname.c_str());
return 1;
}
of.write((char*)_mst_header, MST_HEADER_LEN);
writeData(of);
of.close();
return 0;
}
int8_t MStorage::readFromFile(std::string fname){
std::ifstream ifs;
unsigned char mst_header[MST_HEADER_LEN];
ifs.open(fname.c_str(), std::ios::binary | std::ios::in);
if(!ifs.is_open()) {
fprintf(stderr, "MStorage::%s(): Unable to open %s for reading!\n", __FUNCTION__, fname.c_str());
return 1;
}
ifs.read((char*)mst_header, MST_HEADER_LEN);
if (memcmp(mst_header, _mst_header, MST_HEADER_LEN) != 0) {
fprintf(stderr, "MStorage::%s(): File header is wrong!\n", __FUNCTION__);
ifs.close();
return 2;
} else {
values.clear();
uint8_t selfDtype = 0;
ifs.read((char*)&selfDtype, 1);
if(selfDtype != MDT_GROUP){
fprintf(stderr, "MStorage::%s(): Wrong group data type"
"(0x%02x)!\n", __FUNCTION__, selfDtype);
ifs.close();
return 3;
}
readData(ifs);
ifs.close();
return 0;
}
ifs.close();
return 4;
}
void MStorage::insertRaw(const std::string &key, IMStorageBase *val){
size_t klen = key.size();
if(klen > 0xFF) {
fprintf(stderr, "MStorage::%s(): Key name is too long (%u), skipping\n", __FUNCTION__, klen);
return;
}
MValueMapIterator it = values.find(key);
if(it == end()) {
values[key] = val;
} else { // replacing
if(it->second)
delete it->second;
it->second = val;
// fprintf(stderr, "MStorage::%s(): Value with key \"%s\" is already exists!\n",
// __FUNCTION__, key.c_str());
}
}
IMStorageBase *MStorage::getRaw(const std::string &key){
if(values.find(key) == end()) {
fprintf(stderr, "MStorage::%s(): Value with key \"%s\" not found!\n",
__FUNCTION__, key.c_str());
return NULL;
} else {
return values[key];
}
}
void MStorage::setInt(const std::string &key, uint32_t val) {
insertRaw(key, new MStorageInt32(val));
}
void MStorage::setIntArray(const std::string &key, int32_t *val, uint16_t len)
{
insertRaw(key, new MStorageInt32Array(val, len));
}
void MStorage::setByteArray(const std::string &key, uint8_t *val, uint16_t len)
{
insertRaw(key, new MStorageByteArray(val, len));
}
void MStorage::setDouble(const std::string &key, double val) {
insertRaw(key, new MStorageDouble(val));
}
void MStorage::setByte(const std::string &key, uint8_t val) {
insertRaw(key, new MStorageByte(val));
}
void MStorage::setString(const std::string &key, std::string val) {
insertRaw(key, new MStorageString(val));
}
void MStorage::setGroup(const std::string &key, MStorage *group)
{
insertRaw(key, group);
}
int32_t MStorage::getInt(const std::string &key) {
IMStorageBasicType *bval = getBasicType(key);
return bval ? bval->getInt() : 0;
}
int32_t *MStorage::getIntArray(const std::string &key, uint16_t *len)
{
IMStorageBase *bval = getRaw(key);
if(!bval){
return NULL;
}
if(bval->getType() != MDT_INT32_ARRAY) {
fprintf(stderr, "MStorage::%s(): Value is not INT32 ARRAY!\n", __FUNCTION__);
return NULL;
}
MStorageInt32Array *sval = static_cast<MStorageInt32Array*>(bval);
if(len)
*len = sval->getArrayLength();
return sval->getIntArray();
}
uint8_t *MStorage::getByteArray(const std::string &key, uint16_t *len)
{
IMStorageBase *bval = getRaw(key);
if(!bval){
return NULL;
}
if(bval->getType() != MDT_BYTE_ARRAY) {
fprintf(stderr, "MStorage::%s(): Value is not BYTE ARRAY!\n", __FUNCTION__);
return NULL;
}
MStorageByteArray *sval = static_cast<MStorageByteArray*>(bval);
if(len)
*len = sval->getArrayLength();
return sval->getByteArray();
}
double MStorage::getDouble(const std::string &key) {
IMStorageBasicType *bval = getBasicType(key);
return bval ? bval->getDouble() : 0;
}
uint8_t MStorage::getByte(const std::string &key) {
IMStorageBasicType *bval = getBasicType(key);
return bval ? bval->getByte() : 0;
}
std::string MStorage::getString(const std::string &key) {
IMStorageBase *bval = getRaw(key);
if(!bval){
return "";
}
if(bval->getType() != MDT_STRING) {
fprintf(stderr, "MStorage::%s(): Value is not STRING!\n", __FUNCTION__);
return "";
}
MStorageString *sval = static_cast<MStorageString*>(bval);
return sval->getString();
}
MStorage *MStorage::getGroup(const std::string &key)
{
IMStorageBase *bval = getRaw(key);
if(!bval){
return NULL;
}
if(bval->getType() != MDT_GROUP) {
fprintf(stderr, "MStorage::%s(): Value is not GROUP!\n", __FUNCTION__);
return NULL;
}
MStorage *sval = static_cast<MStorage*>(bval);
return sval;
}
MValueMapIterator MStorage::begin(){
return values.begin();
}
MValueMapIterator MStorage::end(){
return values.end();
}
void MStorage::clear()
{
MValueMapIterator it = begin();
while(it != end()) {
delete it->second;
it++;
}
values.clear();
}
void MStorage::erase(const std::string &key){
IMStorageBase *bval = getRaw(key);
if(bval){
values.erase(key);
delete bval;
}
}
void MStorage::dbgPrintKeys()
{
MValueMapIterator it = begin();
printf("MStorage: [ ");
while(it != end()) {
printf("%s ", it->first.c_str());
it++;
}
printf("]\n");
}
IMStorageBase *MStorage::createByID(uint8_t id) {
switch(id) {
case MDT_INT32:
return new MStorageInt32(0);
case MDT_DOUBLE:
return new MStorageDouble(0);
case MDT_BYTE:
return new MStorageByte(0);
case MDT_STRING:
return new MStorageString("");
case MDT_INT32_ARRAY:
return new MStorageInt32Array(NULL, 0);
case MDT_BYTE_ARRAY:
return new MStorageByteArray(NULL, 0);
case MDT_GROUP:
return new MStorage();
default:
fprintf(stderr, "MStorage::%s(): "
"Unknown data type (0x%02x)!\n", __FUNCTION__, id);
return NULL;
}
}
IMStorageBasicType *MStorage::getBasicType(const std::string &key) {
IMStorageBasicType *bval = dynamic_cast<IMStorageBasicType*>(getRaw(key));
if(!bval) {
fprintf(stderr, "MStorage::%s(): Unable to get Basic type!\n", __FUNCTION__);
return NULL;
}
return bval;
}
MStorageDataType MStorage::getType(){
return MDT_GROUP;
}
void MStorage::writeData(std::ostream &of){
MValueMapIterator it = begin();
uint16_t datalen = getLength();
of.put((char)getType());
of.write((char*)&datalen, sizeof(uint16_t));
while(it != end()) {
size_t klen = it->first.size();
of.put((char)(klen & 0xFF));
for(size_t pos = 0; pos < klen; ++pos) {
of << it->first.at(pos);
}
it->second->writeData(of);
it++;
}
}
void MStorage::readData(std::istream &ifs){
uint16_t blockSize = 0;
uint16_t bytesRead = 0;
ifs.read((char*)&blockSize, sizeof(uint16_t));
while (!ifs.eof() && (bytesRead < blockSize)) {
uint8_t klen;
ifs.read((char*)&klen, 1); // key length
bytesRead += ifs.gcount();
char* key = new char[klen];
ifs.read(key, klen); // key
bytesRead += ifs.gcount();
std::string skey(key, klen);
uint8_t dtype;
ifs.read((char*)&dtype, 1); // data type
bytesRead += ifs.gcount();
IMStorageBase * data = createByID(dtype);
data->readData(ifs); // data
bytesRead += data->getLength();
insertRaw(skey, data);
delete[] key;
}
if(bytesRead != blockSize){
fprintf(stderr, "MStorage::%s(): Group block size missmatch "
"(0x%04x instead of 0x%04x)!\n", __FUNCTION__, bytesRead, blockSize);
}
}
uint16_t MStorage::getLength(){
uint16_t sz = 0;
MValueMapIterator it = begin();
//sz+=1; // self data type
while(it != end()) {
sz+=1; // key len byte
sz+=it->first.size(); // key characters
sz+=1; // data type byte
sz+=it->second->getLength(); // data len
it++;
}
return sz;
}
///////////////////////////////////////////////////////////////////////

218
MStorage.h Normal file

@ -0,0 +1,218 @@
#ifndef MSTORAGE_H
#define MSTORAGE_H
#include <stdint.h>
#include <fstream>
#include <cstring>
#include <string>
#include <cstdio>
#include <map>
#define MST_HEADER {'M', 'S', 'T', 0xFA, 0x33}
#define MST_HEADER_LEN 5
static const unsigned char _mst_header[MST_HEADER_LEN] = MST_HEADER;
enum MStorageDataType {
MDT_INT32 = 0x01,
MDT_DOUBLE = 0x02,
MDT_BYTE = 0x03,
MDT_STRING = 0x04,
MDT_INT32_ARRAY = 0x05,
MDT_BYTE_ARRAY = 0x06,
MDT_GROUP = 0xAF
};
class IMStorageBase {
public:
virtual ~IMStorageBase() {}
virtual MStorageDataType getType() = 0;
virtual void writeData(std::ostream &of) = 0;
virtual void readData(std::istream &ifs) = 0;
virtual uint16_t getLength() = 0;
//virtual void printValue() = 0;
};
class IMStorageBasicType : public IMStorageBase {
public:
virtual uint8_t getByte() = 0;
virtual double getDouble() = 0;
virtual int32_t getInt() = 0;
};
class MStorageInt32 : public IMStorageBasicType {
public:
MStorageInt32(int32_t val);
MStorageDataType getType();
uint8_t getByte();
double getDouble();
int32_t getInt();
void writeData(std::ostream &of);
void readData(std::istream &ifs);
uint16_t getLength();
private:
int32_t val;
};
class MStorageDouble : public IMStorageBasicType {
public:
MStorageDouble(double val);
MStorageDataType getType();
uint8_t getByte();
double getDouble();
int32_t getInt();
void writeData(std::ostream &of);
void readData(std::istream &ifs);
uint16_t getLength();
private:
double val;
};
class MStorageByte : public IMStorageBasicType {
public:
MStorageByte(int8_t val);
MStorageDataType getType();
uint8_t getByte();
double getDouble();
int32_t getInt();
void writeData(std::ostream &of);
void readData(std::istream &ifs);
uint16_t getLength();
private:
int8_t val;
};
class MStorageString : public IMStorageBase {
public:
MStorageString(std::string val);
MStorageDataType getType();
std::string getString();
void writeData(std::ostream &of);
void readData(std::istream &ifs);
uint16_t getLength();
private:
std::string val;
};
class MStorageInt32Array : public IMStorageBase {
public:
MStorageInt32Array(int32_t *data, uint16_t len);
virtual ~MStorageInt32Array();
MStorageDataType getType();
int32_t * getIntArray();
uint16_t getLength();
uint16_t getArrayLength();
void writeData(std::ostream &of);
void readData(std::istream &ifs);
private:
int32_t *val;
uint16_t val_len;
};
class MStorageByteArray : public IMStorageBase {
public:
MStorageByteArray(uint8_t *data, uint16_t len){
if(!data || len == 0){
val_len = 0;
val = NULL;
return;
}
val_len = len;
val = new uint8_t[val_len];
memcpy(val, data, val_len);
}
virtual ~MStorageByteArray(){
delete [] val;
}
MStorageDataType getType(){
return MDT_BYTE_ARRAY;
}
uint8_t * getByteArray(){
return val;
}
uint16_t getLength(){
return val_len + sizeof(uint16_t);
}
uint16_t getArrayLength(){
return val_len;
}
void writeData(std::ostream &of){
of.put((char)getType());
of.write((char*)&val_len, sizeof(uint16_t));
of.write((char*)val, val_len);
}
void readData(std::istream &ifs){
if(val)
delete[] val;
ifs.read((char*)&val_len, sizeof(uint16_t));
val = new uint8_t[val_len];
ifs.read((char*)val, val_len);
}
private:
uint8_t *val;
uint16_t val_len;
};
typedef std::map<const std::string, IMStorageBase*> MValueMap;
typedef MValueMap::iterator MValueMapIterator;
class MStorage : public IMStorageBase {
public:
MStorage();
virtual ~MStorage();
int8_t writeToFile(std::string fname);
int8_t readFromFile(std::string fname);
void insertRaw(const std::string &key, IMStorageBase *val);
IMStorageBase* getRaw(const std::string &key);
void setInt(const std::string &key, uint32_t val);
void setIntArray(const std::string &key, int32_t *val, uint16_t len);
void setByteArray(const std::string &key, uint8_t *val, uint16_t len);
void setDouble(const std::string &key, double val);
void setByte(const std::string &key, uint8_t val);
void setString(const std::string &key, std::string val);
void setGroup(const std::string &key, MStorage *group);
int32_t getInt(const std::string &key);
int32_t* getIntArray(const std::string &key, uint16_t *len);
uint8_t* getByteArray(const std::string &key, uint16_t *len);
double getDouble(const std::string &key);
uint8_t getByte(const std::string &key);
std::string getString(const std::string &key);
MStorage* getGroup(const std::string &key);
MValueMapIterator begin();
MValueMapIterator end();
void clear();
void erase(const std::string &key);
void dbgPrintKeys();
private:
static IMStorageBase* createByID(uint8_t id);
IMStorageBasicType* getBasicType(const std::string &key);
MValueMap values;
// IMStorageBase
public:
MStorageDataType getType();
void writeData(std::ostream &of);
void readData(std::istream &ifs);
uint16_t getLength();
};
#endif // MSTORAGE_H

62
README.md Normal file

@ -0,0 +1,62 @@
MStorage - simple multi-type map storage for some fixed data types
==================================================================
Absolutely no warranty. Use at your own risk.
Written for one small game.
### Supported types:
- 32-bit Signed Integer
- 32-bit Signed Integer Array
- 8-bit Unsigned Integer (Byte)
- 8-bit Unsigned Integer (Byte) Array
- Double
- String (std::string)
### Features:
- Values and groups are associated with keys.
- Grouping. All of types listed above can be grouped.
- Base types are casted automatically to each other.
- Writing to file / reading from file.
- Writing and reading from stream.
## Example usage:
### Assigning and writing to file:
```c++
MStorage mst;
mst.setInt("someInt", 123456);
mst.writeToFile("data.mst");
```
### Reading:
```c++
MStorage mst;
mst.readFromFile("data.mst");
int32_t val = mst.getInt("someInt");
```
### Groups:
```c++
MStorage mst;
MStorage *group = new MStorage();
group->setString("str", "Hello");
mst.setGroup("someGroup", group);
std::string str = mst.getGroup("someGroup")->getString("str");
```
### Iterating:
```c++
MValueMapIterator it = mst.begin();
while(it != mst.end()) {
MStorageBase *val = it->second;
// do something
// type can be discovered via val->getType()
it++;
}
```

6
example/Makefile.linux Normal file

@ -0,0 +1,6 @@
RM = rm -f
TO_NULL = > /dev/null
TARGET_BINARY = example
OS_SEPARATOR= /
-include base.mk

6
example/Makefile.win32 Normal file

@ -0,0 +1,6 @@
RM = del /f
TO_NULL = 2>NUL
TARGET_BINARY = example.exe
OS_SEPARATOR= \\
-include base.mk

48
example/base.mk Normal file

@ -0,0 +1,48 @@
SOURCES = example.cpp ./../MStorage.cpp
LDFLAGS_RELEASE = -s
CDFLAGS_RELEASE = -O2 -Wall
CFLAGS ?= -g -Wall
LDPATH ?= -L.
LDFLAGS ?=
INCLUDES = -I. -I./..
OBJECTS = $(SOURCES:.cpp=.o)
OBJECTS := $(OBJECTS:.c=.o)
DEPS = $(OBJECTS:.o=.d)
TARGET = $(TARGET_BINARY)
all: debug
release: LDFLAGS=$(LDFLAGS_RELEASE)
release: CFLAGS=$(CDFLAGS_RELEASE)
release: debug
debug: $(SOURCES) $(TARGET)
$(TARGET): $(OBJECTS)
$(CXX) $(LDPATH) -o $@ $(OBJECTS) $(LDFLAGS)
.cpp.o:
$(CXX) -c -MMD -MP $(CFLAGS) $(INCLUDES) $< -o $@
.c.o:
$(CC) -c -MMD -MP $(CFLAGS) $(INCLUDES) $< -o $@
.PHONY: clean debug release
clean:
$(RM) *.o $(TO_NULL)
$(RM) *.d $(TO_NULL)
$(RM) .$(OS_SEPARATOR)..$(OS_SEPARATOR)*.o $(TO_NULL)
$(RM) .$(OS_SEPARATOR)..$(OS_SEPARATOR)*.d $(TO_NULL)
$(RM) $(TARGET_BINARY) $(TO_NULL)
$(RM) data.mst $(TO_NULL)
-include $(DEPS)

57
example/example.cpp Normal file

@ -0,0 +1,57 @@
#include "MStorage.h"
#include <cstdio>
#include <stdint.h>
void print_fieds(MStorage *mst) {
printf("someString: %s\n", mst->getString("someString").c_str());
printf("someInt: %d\n", mst->getInt("someInt"));
printf("someByte: 0x%x\n", mst->getByte("someByte"));
printf("someGroup: \n");
MStorage* group = mst->getGroup("someGroup");
printf(" someDouble: %.9f\n", group->getDouble("someDouble"));
//or mst->getGroup("someGroup")->getDouble("someDouble")
int32_t* arr;
uint16_t arr_len;
arr = group->getIntArray("someIntArray", &arr_len);
if (arr) {
printf(" someIntArray: ");
for (int i = 0; i < arr_len; ++i) {
printf("%d ", arr[i]);
}
printf("\n");
}
}
int main(int argc, char const *argv[]) {
MStorage *storage;
printf("\n## write test ##\n");
storage = new MStorage();
storage->setString("someString", "Hello world!");
storage->setInt("someInt", 123456);
storage->setByte("someByte", 0xA4);
MStorage *group = new MStorage(); // you can create groups in groups too
group->setDouble("someDouble", 3.141592653);
int32_t _ints[] = {42, 34, 32323, 5573453};
group->setIntArray("someIntArray", _ints, 4); // array is being copied
storage->setGroup("someGroup", group);
print_fieds(storage);
storage->writeToFile("data.mst");
delete storage; // subfields are deleted automatically
printf("\n## read test ##\n");
storage = new MStorage();
storage->readFromFile("data.mst");
print_fieds(storage);
delete storage;
return 0;
}