Harmonic Flow Framework (libhffwk)
Cross platform C++ 2D Game Engine Framework
GenericPersistenceLayer.cpp
1 /*
2  Harmonic Flow Framework
3  Copyright (C) 2011-2018 Andreas Widen <andreas@harmonicflow.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
22 
23 #include "GenericStorage.h"
24 #include "util/StringUtil.h"
25 
26 #include <assert.h>
27 #include <iostream>
28 #include <sstream>
29 #include <fstream>
30 
31 #include "platform/FileDirUtils.h"
32 
33 using namespace HFCore;
34 
35 #include "debug/CrtDbgNew.h"
36 
38  const UString &gameName,
39  const UString &filename)
40 {
41  // Get filedirutils handler.
42  std::wstring basePath = HFCORE_FDU->getAppDataFolder();
43 #if defined(HF_PLATFORM_LINUX)
44  std::wstring pathToCreate = basePath + L"/." + publisherName.wc_str() + L"/";
45 #else
46  std::wstring pathToCreate = basePath + L"/" + publisherName.wc_str() + L"/";
47 #endif
48 
49  // Create publisher dir first.
50  HFCORE_FDU->createDirectory(pathToCreate);
51 
52  // Also create gamename path
53  pathToCreate = pathToCreate + gameName.wc_str() + L"/";
54  HFCORE_FDU->createDirectory(pathToCreate);
55 
56  // Remember full path to filename
57  pathToCreate = pathToCreate + filename.wc_str();
58  mFileName = pathToCreate.c_str();
59 
60  load();
61 }
62 
64 {
65 }
66 
67 bool GenericPersistenceLayer::remove(const std::string &name, bool persist)
68 {
69  // find the name:
70  StringUtil::StringMap::iterator iter = mValues.find(name);
71 
72  // if it doesn't exist
73  if (iter == mValues.end())
74  {
75  return false;
76  }
77 
78  // erase it:
79  mValues.erase(iter);
80 
81  if (persist)
82  {
83  this->persist();
84  }
85 
86  // success:
87  return true;
88 }
89 
90 void GenericPersistenceLayer::putString(const std::string &name, const std::string &value,
91  bool persist)
92 {
93  assert(StringUtil::trim(name).size() > 0);
94  if (mValues[name] != value)
95  {
96  mValues[name] = value;
97  if (persist)
98  {
99  this->persist();
100  }
101  }
102 }
103 
104 const std::string GenericPersistenceLayer::getString(const std::string &name)
105 {
106  StringUtil::StringMap::iterator iter = mValues.find(name);
107  if (iter != mValues.end())
108  {
109  return iter->second;
110  }
111  else
112  {
113  return std::string("");
114  }
115 }
116 
117 void GenericPersistenceLayer::load()
118 {
119  int8_hf *deCompressedData;
120  int32_hf deCompressedDataSize;
121 
123  &deCompressedData,
124  &deCompressedDataSize);
125 
126  if (deCompressedData != NULL && deCompressedDataSize > 0)
127  parse(deCompressedData, deCompressedDataSize);
128 
129  HF_SAFE_DELETE_ARR(deCompressedData);
130 }
131 
132 void GenericPersistenceLayer::save()
133 {
134  envDebugLog("------------------------ persisting data ----------------------------\r\n");
135  std::ostringstream writeStr;
136  for (StringUtil::StringMap::iterator i = mValues.begin(); i != mValues.end(); i++)
137  {
138  if (i->first.length() != 0) // skip null values
139  {
140  assert(i->first.length() > 0);
141  writeStr << i->first.length() << "," << i->first;
142  writeStr << i->second.length() << "," << i->second;
143  envDebugLog("%s = %s\r\n", i->first.c_str(), i->second.c_str());
144  }
145  }
146  envDebugLog("---------------------------------------------------------------------\r\n");
147 
148  // mark the end of the data:
149  writeStr << ",0.";
150 
151  if (mValues.size() > 0)
152  {
153  // zlib compress:
154  int8_hf *compressedData = NULL;
155  int32_hf compressedDataSize = 0;
156  Environment::zlibCompress(writeStr.str().c_str(),
157  (int32_hf)writeStr.str().size(),
158  &compressedData,
159  &compressedDataSize);
160 
161  // persist:
162  Environment::saveFile(mFileName.toUtf8(),
163  compressedData,
164  compressedDataSize);
165 
166  // delete zlib compressed data:
167  HF_SAFE_DELETE_ARR(compressedData);
168  }
169 }
170 
171 void GenericPersistenceLayer::parse(int8_hf *data, int32_hf size)
172 {
173  int32_hf namePos;
174  int32_hf nameSize;
175  int32_hf valuePos;
176  int32_hf valueSize;
177 
178  envDebugLog("---------------- loading persistent data ----------------------------\r\n");
179 
180  for (int32_hf pos = 0; pos < size;)
181  {
182  // read the name size:
183  nameSize = readInt(data, &pos);
184  if (nameSize == 0)
185  {
186  // we've reached the end:
187  break;
188  }
189 
190  // skip the comma:
191  pos++;
192 
193  // remember beginning of name:
194  namePos = pos;
195 
196  // advance the position:
197  pos += nameSize;
198 
199  // read the value size:
200  valueSize = readInt(data, &pos);
201  if (valueSize == 0)
202  {
203  envDebugLog("bad data in %s at position %d (zero length value)\r\n",
204  mFileName.toUtf8(),
205  pos);
206  return;
207  }
208 
209  // skip the comma:
210  pos++;
211 
212  // remember beginning of value:
213  valuePos = pos;
214 
215  // advance the position:
216  pos += valueSize;
217 
218  // remember the name/value pair:
219  std::string name = std::string(data + namePos, nameSize);
220  std::string value = std::string(data + valuePos, valueSize);
221  mValues[name] = value;
222 
223  envDebugLog("%s = %s\r\n", name.c_str(), value.c_str());
224  }
225 
226  envDebugLog("---------------------------------------------------------------------\r\n");
227 }
228 
229 int32_hf GenericPersistenceLayer::readInt(int8_hf *data, int32_hf *pos)
230 {
231  int32_hf value = 0;
232  while (data[*pos] >= '0' && data[*pos] <= '9')
233  {
234  value *= 10;
235  value += data[*pos] - '0';
236  (*pos)++;
237  }
238 
239  return value;
240 }
241 
243 {
244  return (int32_hf)mValues.size();
245 }
246 
248 {
249  StringUtil::StringMap::iterator iter = mValues.begin();
250  for (int32_hf x = 0; x < i; x++)
251  {
252  iter++;
253  }
254  return iter->first;
255 }
256 
258 {
259  save();
260 }
virtual ~GenericPersistenceLayer()
Destructor.
Interface which implements base class PersistenceLayer.
Interface for unicode string class UString.
Definition: UString.h:35
virtual void putString(const std::string &name, const std::string &value, bool persist=false)
Put string name / value pair into map.
int int32_hf
A type definition for int.
Definition: HFDataTypes.h:349
Interface which implements base class Storage.
static std::string trim(const std::string &str)
Trim string left and right.
Definition: StringUtil.cpp:319
const wchar_t * wc_str() const
Get the unicode widechar string.
Definition: UString.cpp:579
virtual int32_hf getKeyCount()
Get the size of name / value pair map.
virtual void persist()
Persist / save name / value pair map to disk.
#define HF_SAFE_DELETE_ARR(p)
Check if not NULL, delete array and set to NULL.
Definition: HFDataTypes.h:56
static bool loadzlibCompressedFile(const int8_hf *fileName, int8_hf **outData, int32_hf *outDataSize)
Load a zlib compressed file and return raw data.
#define NULL
Convenient define for 0.
Definition: HFDataTypes.h:42
virtual bool remove(const std::string &name, bool persist=false)
Remove name / value pair from map for given name.
const int8_hf * toUtf8() const
Get the utf8 encoded string.
Definition: UString.cpp:574
char int8_hf
A type definition for char.
Definition: HFDataTypes.h:329
virtual const std::string getString(const std::string &name)
Get string value for given name.
static bool zlibCompress(const int8_hf *inData, int32_hf inDataSize, int8_hf **outData, int32_hf *outDataSize, int32_hf compLevel=Z_DEFAULT_COMPRESSION)
Compress inData using zlib.
static bool saveFile(const int8_hf *fileName, const int8_hf *inData, int32_hf inDataSize)
Store and save inData in a new file with fileName.
GenericPersistenceLayer(const UString &publisherName, const UString &gameName, const UString &filename)
Constructor.
Definition: Actor.h:34
#define HFCORE_FDU
Get HFCore::FileDirUtils instance shortcut macro.
Definition: Environment.h:83
#define envDebugLog(format, args...)
Shortcut macro for logging to &#39;debug.log&#39;.
Definition: Environment.h:2364
virtual const std::string getKey(int32_hf i)
Get index name of map for given index.
Interface for string related helper methods.
Interface useful for generic directory and file operations.