• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 13444791905

20 Feb 2025 09:14PM UTC coverage: 58.766% (-0.02%) from 58.783%
13444791905

push

github

web-flow
Datafile save fixes (#768)

* create datafile directory if it does not exists during worldsave, before
writing the likely empty file

* check existing of datafiles during startup.
added test for just creating a datafile without adding content

* breaking changes added

5 of 9 new or added lines in 1 file covered. (55.56%)

13 existing lines in 4 files now uncovered.

42276 of 71939 relevant lines covered (58.77%)

388302.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.16
/pol-core/pol/module/datastore.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
5
 * - 2006/09/26 Shinigami: GCC 3.4.x fix - added "template<>" to TmplExecutorModule
6
 * - 2007/06/17 Shinigami: added config.world_data_path
7
 * - 2009/12/21 Turley:    ._method() call fix
8
 */
9

10

11
#include "datastore.h"
12
#include <exception>
13
#include <filesystem>
14
#include <fstream>
15
#include <stddef.h>
16

17
#include "../../bscript/berror.h"
18
#include "../../bscript/bobject.h"
19
#include "../../bscript/bstruct.h"
20
#include "../../bscript/executor.h"
21
#include "../../bscript/impstr.h"
22
#include "../../bscript/objmethods.h"
23
#include "../../clib/cfgelem.h"
24
#include "../../clib/cfgfile.h"
25
#include "../../clib/fileutil.h"
26
#include "../../clib/rawtypes.h"
27
#include "../../clib/stlutil.h"
28
#include "../../clib/streamsaver.h"
29
#include "../../plib/pkg.h"
30
#include "../../plib/systemstate.h"
31
#include "../globals/ucfg.h"
32
#include "../proplist.h"
33
#include "datastoreimp.h"
34

35
#include <module_defs/datafile.h>
36

37
namespace Pol
38
{
39
namespace Module
40
{
41
///
42
/// Datastore
43
///
44
///  datastore files are stored in
45
///     config.world_data_path + ds/fname.txt
46
///     config.world_data_path + ds/{pkgname}/fname.txt
47
///
48

49
Bscript::BApplicObjType datafileref_type;
50
Bscript::BApplicObjType datafileelem_type;
51

52
DataFileContents::DataFileContents( DataStoreFile* dsf ) : dsf( dsf ), dirty( false ) {}
5✔
53

54
DataFileContents::~DataFileContents()
10✔
55
{
56
  elements_by_integer.clear();
5✔
57
  elements_by_string.clear();
5✔
58
}
10✔
59

60
size_t DataFileContents::estimateSize() const
×
61
{
62
  size_t size = sizeof( DataStoreFile* ) /*dsf*/
×
63
                + sizeof( bool );        /*dirty*/
64

65
  size += Clib::memsize( elements_by_string );
×
66
  for ( const auto& ele : elements_by_string )
×
67
  {
68
    if ( ele.second.get() != nullptr )
×
69
      size += ele.second->proplist.estimatedSize();
×
70
  }
71
  size += Clib::memsize( elements_by_integer );
×
72
  return size;
×
73
}
74

75
void DataFileContents::load( Clib::ConfigFile& cf )
2✔
76
{
77
  Clib::ConfigElem elem;
2✔
78

79
  while ( cf.read( elem ) )
6✔
80
  {
81
    DataFileElement* delem = new DataFileElement( elem );
4✔
82

83
    if ( dsf->flags & DF_KEYTYPE_INTEGER )
4✔
84
    {
85
      elements_by_integer[atol( elem.rest() )].set( delem );
2✔
86
    }
87
    else
88
    {
89
      elements_by_string[elem.rest()].set( delem );
2✔
90
    }
91
  }
92
}
2✔
93

94
void DataFileContents::save( Clib::StreamWriter& sw )
3✔
95
{
96
  for ( const auto& element : elements_by_string )
5✔
97
  {
98
    sw.begin( "Element", element.first );
2✔
99
    element.second->printOn( sw );
2✔
100
    sw.end();
2✔
101
  }
102

103
  for ( const auto& element : elements_by_integer )
5✔
104
  {
105
    sw.begin( "Element", element.first );
2✔
106
    element.second->printOn( sw );
2✔
107
    sw.end();
2✔
108
  }
109
}
3✔
110

111
Bscript::BObjectImp* DataFileContents::methodCreateElement( int key )
2✔
112
{
113
  ElementsByInteger::iterator itr = elements_by_integer.find( key );
2✔
114
  DataFileElementRef dfelem;
2✔
115
  if ( itr == elements_by_integer.end() )
2✔
116
  {
117
    dfelem.set( new DataFileElement );
2✔
118
    elements_by_integer[key] = dfelem;
2✔
119
    dirty = true;
2✔
120
  }
121
  else
122
  {
123
    dfelem = ( *itr ).second;
×
124
  }
125
  return new DataElemRefObjImp( DataFileContentsRef( this ), dfelem );
4✔
126
}
2✔
127

128
Bscript::BObjectImp* DataFileContents::methodCreateElement( const std::string& key )
2✔
129
{
130
  ElementsByString::iterator itr = elements_by_string.find( key );
2✔
131
  DataFileElementRef dfelem;
2✔
132
  if ( itr == elements_by_string.end() )
2✔
133
  {
134
    dfelem.set( new DataFileElement );
2✔
135
    elements_by_string[key] = dfelem;
2✔
136
    dirty = true;
2✔
137
  }
138
  else
139
  {
140
    dfelem = ( *itr ).second;
×
141
  }
142
  return new DataElemRefObjImp( DataFileContentsRef( this ), dfelem );
4✔
143
}
2✔
144

145

146
Bscript::BObjectImp* DataFileContents::methodFindElement( int key )
2✔
147
{
148
  ElementsByInteger::iterator itr = elements_by_integer.find( key );
2✔
149
  if ( itr != elements_by_integer.end() )
2✔
150
  {
151
    DataFileElementRef dfelem = ( *itr ).second;
2✔
152
    return new DataElemRefObjImp( DataFileContentsRef( this ), dfelem );
2✔
153
  }
2✔
154
  else
155
  {
156
    return new Bscript::BError( "Element not found" );
×
157
  }
158
}
159

160
Bscript::BObjectImp* DataFileContents::methodFindElement( const std::string& key )
2✔
161
{
162
  ElementsByString::iterator itr = elements_by_string.find( key );
2✔
163
  if ( itr != elements_by_string.end() )
2✔
164
  {
165
    DataFileElementRef dfelem = ( *itr ).second;
2✔
166
    return new DataElemRefObjImp( DataFileContentsRef( this ), dfelem );
2✔
167
  }
2✔
168
  else
169
  {
170
    return new Bscript::BError( "Element not found" );
×
171
  }
172
}
173

174

175
Bscript::BObjectImp* DataFileContents::methodDeleteElement( int key )
×
176
{
177
  if ( elements_by_integer.erase( key ) )
×
178
  {
179
    dirty = true;
×
180
    return new Bscript::BLong( 1 );
×
181
  }
182
  else
183
    return new Bscript::BError( "Element not found" );
×
184
}
185

186
Bscript::BObjectImp* DataFileContents::methodDeleteElement( const std::string& key )
×
187
{
188
  if ( elements_by_string.erase( key ) )
×
189
  {
190
    dirty = true;
×
191
    return new Bscript::BLong( 1 );
×
192
  }
193
  else
194
    return new Bscript::BError( "Element not found" );
×
195
}
196

197
Bscript::BObjectImp* DataFileContents::methodKeys() const
2✔
198
{
199
  std::unique_ptr<Bscript::ObjArray> arr( new Bscript::ObjArray );
2✔
200

201
  for ( ElementsByString::const_iterator citr = elements_by_string.begin();
2✔
202
        citr != elements_by_string.end(); ++citr )
4✔
203
  {
204
    arr->addElement( new Bscript::String( ( *citr ).first ) );
2✔
205
  }
206

207
  for ( ElementsByInteger::const_iterator citr = elements_by_integer.begin();
2✔
208
        citr != elements_by_integer.end(); ++citr )
4✔
209
  {
210
    arr->addElement( new Bscript::BLong( ( *citr ).first ) );
2✔
211
  }
212

213
  return arr.release();
4✔
214
}
2✔
215

216

217
DataFileRefObjImp::DataFileRefObjImp( DataFileContentsRef dfcontents )
6✔
218
    : DataFileRefObjImpBase( &datafileref_type, dfcontents )
6✔
219
{
220
}
6✔
221

222
const char* DataFileRefObjImp::typeOf() const
×
223
{
224
  return "DataFileRef";
×
225
}
226
u8 DataFileRefObjImp::typeOfInt() const
×
227
{
228
  return OTDataFileRef;
×
229
}
230

231
Bscript::BObjectImp* DataFileRefObjImp::copy() const
×
232
{
233
  return new DataFileRefObjImp( obj_ );
×
234
}
235

236
Bscript::BObjectImp* DataFileRefObjImp::call_method_id( const int id, Bscript::Executor& ex,
10✔
237
                                                        bool /*forcebuiltin*/ )
238
{
239
  switch ( id )
10✔
240
  {
241
  case Bscript::MTH_CREATEELEMENT:
4✔
242
    if ( !ex.hasParams( 1 ) )
4✔
243
    {
244
      return new Bscript::BError( "not enough parameters to datafile.createelement(key)" );
×
245
    }
246
    if ( obj_->dsf->flags & DF_KEYTYPE_INTEGER )
4✔
247
    {
248
      int key;
249
      if ( !ex.getParam( 0, key ) )
2✔
250
      {
251
        return new Bscript::BError( "datafile.createelement(key): key must be an Integer" );
×
252
      }
253
      return obj_->methodCreateElement( key );
2✔
254
    }
255
    else
256
    {
257
      const Bscript::String* key;
258
      if ( !ex.getStringParam( 0, key ) )
2✔
259
      {
260
        return new Bscript::BError( "datafile.createelement(key): key must be a String" );
×
261
      }
262
      return obj_->methodCreateElement( key->value() );
2✔
263
    }
264
    break;
265
  case Bscript::MTH_FINDELEMENT:
4✔
266
    if ( !ex.hasParams( 1 ) )
4✔
267
    {
268
      return new Bscript::BError( "not enough parameters to datafile.findelement(key)" );
×
269
    }
270
    if ( obj_->dsf->flags & DF_KEYTYPE_INTEGER )
4✔
271
    {
272
      int key;
273
      if ( !ex.getParam( 0, key ) )
2✔
274
      {
275
        return new Bscript::BError( "datafile.findelement(key): key must be an Integer" );
×
276
      }
277
      return obj_->methodFindElement( key );
2✔
278
    }
279
    else
280
    {
281
      const Bscript::String* key;
282
      if ( !ex.getStringParam( 0, key ) )
2✔
283
      {
284
        return new Bscript::BError( "datafile.findelement(key): key must be a String" );
×
285
      }
286
      return obj_->methodFindElement( key->value() );
2✔
287
    }
288
    break;
289
  case Bscript::MTH_DELETEELEMENT:
×
290
    if ( !ex.hasParams( 1 ) )
×
291
    {
292
      return new Bscript::BError( "not enough parameters to datafile.deleteelement(key)" );
×
293
    }
294
    if ( obj_->dsf->flags & DF_KEYTYPE_INTEGER )
×
295
    {
296
      int key;
297
      if ( !ex.getParam( 0, key ) )
×
298
      {
299
        return new Bscript::BError( "datafile.deleteelement(key): key must be an Integer" );
×
300
      }
301
      return obj_->methodDeleteElement( key );
×
302
    }
303
    else
304
    {
305
      const Bscript::String* key;
306
      if ( !ex.getStringParam( 0, key ) )
×
307
      {
308
        return new Bscript::BError( "datafile.deleteelement(key): key must be a String" );
×
309
      }
310
      return obj_->methodDeleteElement( key->value() );
×
311
    }
312
    break;
313
  case Bscript::MTH_KEYS:
2✔
314
    return obj_->methodKeys();
2✔
315
  default:
×
316
    return nullptr;
×
317
  }
318
}
319

320
Bscript::BObjectImp* DataFileRefObjImp::call_method( const char* methodname, Bscript::Executor& ex )
×
321
{
322
  Bscript::ObjMethod* objmethod = Bscript::getKnownObjMethod( methodname );
×
323
  if ( objmethod != nullptr )
×
324
    return this->call_method_id( objmethod->id, ex );
×
325
  else
326
    return nullptr;
×
327
}
328

329

330
DataElemRefObjImp::DataElemRefObjImp( DataFileContentsRef dfcontents, DataFileElementRef dfelem )
8✔
331
    : DataElemRefObjImpBase( &datafileelem_type, DataFileElemObj( dfcontents, dfelem ) )
8✔
332
{
333
}
8✔
334
const char* DataElemRefObjImp::typeOf() const
×
335
{
336
  return "DataElemRef";
×
337
}
338
u8 DataElemRefObjImp::typeOfInt() const
×
339
{
340
  return OTDataElemRef;
×
341
}
342
Bscript::BObjectImp* DataElemRefObjImp::copy() const
×
343
{
344
  return new DataElemRefObjImp( obj_.dfcontents, obj_.dfelem );
×
345
}
346

347
Bscript::BObjectImp* DataElemRefObjImp::call_method_id( const int id, Bscript::Executor& ex,
12✔
348
                                                        bool /*forcebuiltin*/ )
349
{
350
  bool changed = false;
12✔
351
  Bscript::BObjectImp* res = CallPropertyListMethod_id( obj_.dfelem->proplist, id, ex, changed );
12✔
352
  if ( changed )
12✔
353
    obj_.dfcontents->dirty = true;
6✔
354
  return res;
12✔
355
}
356

357
Bscript::BObjectImp* DataElemRefObjImp::call_method( const char* methodname, Bscript::Executor& ex )
×
358
{
359
  bool changed = false;
×
360
  Bscript::BObjectImp* res =
361
      CallPropertyListMethod( obj_.dfelem->proplist, methodname, ex, changed );
×
362
  if ( changed )
×
363
    obj_.dfcontents->dirty = true;
×
364
  return res;
×
365
}
366

367
DataFileExecutorModule::DataFileExecutorModule( Bscript::Executor& exec )
1,497✔
368
    : Bscript::TmplExecutorModule<DataFileExecutorModule, Bscript::ExecutorModule>( exec )
1,497✔
369
{
370
}
1,497✔
371

372
DataStoreFile* DataFileExecutorModule::GetDataStoreFile( const std::string& inspec )
×
373
{
374
  std::string descriptor;
×
375

376
  const Plib::Package* spec_pkg = nullptr;
×
377
  std::string spec_filename;
×
378
  if ( !Plib::pkgdef_split( inspec, exec.prog()->pkg, &spec_pkg, &spec_filename ) )
×
379
  {
380
    return nullptr;  // new BError( "Error in descriptor" );
×
381
  }
382
  if ( spec_pkg == nullptr )
×
383
  {
384
    // ::filename
385
    descriptor = "::" + spec_filename;
×
386
  }
387
  else
388
  {
389
    // :somepkg:filename
390
    descriptor = ":" + spec_pkg->name() + ":" + spec_filename;
×
391
  }
392

393
  Core::DataStore::iterator itr = Core::configurationbuffer.datastore.find( descriptor );
×
394
  if ( itr != Core::configurationbuffer.datastore.end() )
×
395
  {
396
    DataStoreFile* dsf = ( *itr ).second;
×
397
    return dsf;
×
398
  }
399
  else
400
  {
401
    return nullptr;
×
402
  }
403
}
×
404

405
Bscript::BObjectImp* DataFileExecutorModule::mf_ListDataFiles()
×
406
{
407
  std::unique_ptr<Bscript::ObjArray> file_list( new Bscript::ObjArray );
×
408
  for ( Core::DataStore::iterator itr = Core::configurationbuffer.datastore.begin();
×
409
        itr != Core::configurationbuffer.datastore.end(); ++itr )
×
410
  {
411
    DataStoreFile* dsf = ( *itr ).second;
×
412
    std::unique_ptr<Bscript::BStruct> file_name( new Bscript::BStruct );
×
413
    file_name->addMember( "pkg", new Bscript::String( dsf->pkgname ) );
×
414
    file_name->addMember( "name", new Bscript::String( dsf->name ) );
×
415
    file_name->addMember( "descriptor", new Bscript::String( dsf->descriptor ) );
×
416

417
    file_list->addElement( file_name.release() );
×
418
  }
×
419
  return file_list.release();
×
420
}
×
421

422
Bscript::BObjectImp* DataFileExecutorModule::mf_CreateDataFile()
3✔
423
{
424
  const Bscript::String* strob;
425
  int flags;
426
  if ( getStringParam( 0, strob ) && getParam( 1, flags ) )
3✔
427
  {
428
    try
429
    {
430
      std::string descriptor;
3✔
431
      std::string directory;
3✔
432
      std::string d_ds;
3✔
433
      const std::string& inspec = strob->value();
3✔
434

435
      const Plib::Package* spec_pkg = nullptr;
3✔
436
      std::string spec_filename;
3✔
437
      if ( !Plib::pkgdef_split( inspec, exec.prog()->pkg, &spec_pkg, &spec_filename ) )
3✔
438
      {
439
        return new Bscript::BError( "Error in descriptor" );
×
440
      }
441
      if ( spec_pkg == nullptr )
3✔
442
      {
443
        // ::filename
444
        descriptor = "::" + spec_filename;
×
445
        directory = Plib::systemstate.config.world_data_path + "ds/";
×
446
      }
447
      else
448
      {
449
        // :somepkg:filename
450
        descriptor = ":" + spec_pkg->name() + ":" + spec_filename;
3✔
451
        d_ds = Plib::systemstate.config.world_data_path + "ds/";
3✔
452
        directory = Plib::systemstate.config.world_data_path + "ds/" + spec_pkg->name() + "/";
3✔
453
      }
454
      if ( !Clib::FileExists( directory.c_str() ) )
3✔
455
      {
456
        if ( !d_ds.empty() )
1✔
457
          Clib::MakeDirectory( d_ds.c_str() );
1✔
458
        Clib::MakeDirectory( directory.c_str() );
1✔
459
      }
460

461
      DataStoreFile* dsf = nullptr;
3✔
462

463
      Core::DataStore::iterator itr = Core::configurationbuffer.datastore.find( descriptor );
3✔
464
      if ( itr != Core::configurationbuffer.datastore.end() )
3✔
465
      {
466
        dsf = ( *itr ).second;
×
467
      }
468
      else
469
      {
470
        // create a new one
471
        dsf = new DataStoreFile( descriptor, spec_pkg, spec_filename, flags );
3✔
472
        Core::configurationbuffer.datastore[descriptor] = dsf;
3✔
473
      }
474

475
      // didn't find it, time to go open or create.
476
      if ( !dsf->loaded() )
3✔
477
        dsf->load();
3✔
478

479
      return new DataFileRefObjImp( dsf->dfcontents );
3✔
480
    }
3✔
481
    catch ( std::exception& ex )
×
482
    {
483
      std::string message = std::string( "An exception occurred: " ) + ex.what();
×
484
      return new Bscript::BError( message );
×
485
    }
×
486
  }
487
  else
488
  {
489
    return new Bscript::BError( "Invalid parameter type" );
×
490
  }
491
}
492

493
Bscript::BObjectImp* DataFileExecutorModule::mf_OpenDataFile()
3✔
494
{
495
  const Bscript::String* strob;
496
  if ( getStringParam( 0, strob ) )
3✔
497
  {
498
    try
499
    {
500
      std::string descriptor;
3✔
501
      //      string directory;
502
      const std::string& inspec = strob->value();
3✔
503

504
      const Plib::Package* spec_pkg = nullptr;
3✔
505
      std::string spec_filename;
3✔
506
      if ( !Plib::pkgdef_split( inspec, exec.prog()->pkg, &spec_pkg, &spec_filename ) )
3✔
507
      {
508
        return new Bscript::BError( "Error in descriptor" );
×
509
      }
510
      if ( spec_pkg == nullptr )
3✔
511
      {
512
        // ::filename
513
        descriptor = "::" + spec_filename;
×
514
      }
515
      else
516
      {
517
        // :somepkg:filename
518
        descriptor = ":" + spec_pkg->name() + ":" + spec_filename;
3✔
519
      }
520

521
      Core::DataStore::iterator itr = Core::configurationbuffer.datastore.find( descriptor );
3✔
522
      if ( itr != Core::configurationbuffer.datastore.end() )
3✔
523
      {
524
        DataStoreFile* dsf = ( *itr ).second;
3✔
525
        // didn't find it, time to go open or create.
526
        if ( !dsf->loaded() )
3✔
527
          dsf->load();
2✔
528
        return new DataFileRefObjImp( dsf->dfcontents );
3✔
529
      }
530
      else
531
      {
532
        return new Bscript::BError( "Datafile does not exist" );
×
533
      }
534
    }
3✔
535
    catch ( std::exception& ex )
×
536
    {
537
      return new Bscript::BError( std::string( "An exception occurred" ) + ex.what() );
×
538
    }
×
539
  }
540
  else
541
  {
542
    return new Bscript::BError( "Invalid parameter type" );
×
543
  }
544
}
545

546
Bscript::BObjectImp* DataFileExecutorModule::mf_UnloadDataFile()
×
547
{
548
  const Bscript::String* strob;
549
  if ( getStringParam( 0, strob ) )
×
550
  {
551
    DataStoreFile* dsf = GetDataStoreFile( strob->value() );
×
552
    if ( !dsf )
×
553
      return new Bscript::BError( "Unable to find data store file" );
×
554

555
    dsf->unload = true;
×
556
    return new Bscript::BLong( 1 );
×
557
  }
558
  else
559
  {
560
    return new Bscript::BError( "Invalid parameter type" );
×
561
  }
562
}
563

564
DataStoreFile::DataStoreFile( Clib::ConfigElem& elem )
3✔
565
    : descriptor( elem.remove_string( "Descriptor" ) ),
3✔
566
      name( elem.remove_string( "name" ) ),
3✔
567
      pkgname( elem.remove_string( "package", "" ) ),
3✔
568
      pkg( Plib::find_package( pkgname ) ),
3✔
569
      version( elem.remove_ushort( "Version" ) ),
3✔
570
      oldversion( elem.remove_ushort( "OldVersion" ) ),
3✔
571
      flags( elem.remove_ulong( "Flags" ) ),
3✔
572
      unload( false ),
3✔
573
      delversion( 0 )
3✔
574
{
575
}
3✔
576

577
DataStoreFile::DataStoreFile( const std::string& descriptor, const Plib::Package* pkg,
3✔
578
                              const std::string& name, int flags )
3✔
579
    : descriptor( descriptor ),
3✔
580
      name( name ),
3✔
581
      pkgname( "" ),
3✔
582
      pkg( pkg ),
3✔
583
      version( 0 ),
3✔
584
      oldversion( 0 ),
3✔
585
      flags( flags ),
3✔
586
      unload( false ),
3✔
587
      delversion( 0 )
3✔
588
{
589
  if ( pkg != nullptr )
3✔
590
    pkgname = pkg->name();
3✔
591
}
3✔
592

593
bool DataStoreFile::loaded() const
11✔
594
{
595
  return dfcontents.get() != nullptr;
11✔
596
}
597

598
void DataStoreFile::load()
5✔
599
{
600
  if ( loaded() )
5✔
601
    return;
×
602

603
  dfcontents.set( new DataFileContents( this ) );
5✔
604

605
  std::string fn = filename();
5✔
606
  if ( Clib::FileExists( fn.c_str() ) )
5✔
607
  {
608
    Clib::ConfigFile cf( filename().c_str(), "Element" );
2✔
609
    dfcontents->load( cf );
2✔
610
  }
2✔
611
  else
612
  {
613
    // just force an empty file to be written
614
    dfcontents->dirty = true;
3✔
615
  }
616
}
5✔
617

618
DataStoreFile::~DataStoreFile()
6✔
619
{
620
  dfcontents.clear();
6✔
621
}
6✔
622

623
void DataStoreFile::printOn( Clib::StreamWriter& sw ) const
6✔
624
{
625
  sw.begin( "DataFile" );
6✔
626
  sw.add( "Descriptor", descriptor );
6✔
627
  sw.add( "Name", name );
6✔
628

629
  if ( !pkgname.empty() )
6✔
630
    sw.add( "Package", pkgname );
6✔
631

632
  sw.add( "Flags", flags );
6✔
633
  sw.add( "Version", version );
6✔
634
  sw.add( "OldVersion", oldversion );
6✔
635
  sw.end();
6✔
636
}
6✔
637

638
std::string DataStoreFile::filename( unsigned ver ) const
19✔
639
{
640
  std::string tmp = Plib::systemstate.config.world_data_path + "ds/";
19✔
641
  if ( pkg != nullptr )
19✔
642
    tmp += pkg->name() + "/";
19✔
643
  tmp += name + "." + Clib::tostring( ver % 10 ) + ".txt";
19✔
644
  return tmp;
19✔
645
}
×
646

647
std::string DataStoreFile::filename() const
16✔
648
{
649
  return filename( version );
16✔
650
}
651

652
void DataStoreFile::save() const
3✔
653
{
654
  auto path = std::filesystem::path( filename() );
3✔
655
  path.remove_filename();
3✔
656
  if ( !std::filesystem::exists( path ) )
3✔
NEW
657
    std::filesystem::create_directories( path );
×
658

659
  Clib::StreamWriter sw( filename() );
3✔
660
  dfcontents->save( sw );
3✔
661
}
3✔
662

663
size_t DataStoreFile::estimateSize() const
×
664
{
665
  size_t size = descriptor.capacity() + name.capacity() + pkgname.capacity() +
×
666
                sizeof( Plib::Package* ) /*pkg*/
667
                + 3 * sizeof( unsigned ) /*version oldversion delversion*/
668
                + sizeof( int )          /*flags*/
669
                + sizeof( bool )         /*unload*/
670
                + sizeof( DataFileContentsRef );
×
671
  if ( dfcontents.get() )
×
672
    size += dfcontents->estimateSize();
×
673
  return size;
×
674
}
675

676

677
DataFileElement::DataFileElement() : proplist( Core::CPropProfiler::Type::DATAFILEELEMENT ) {}
4✔
678

679
DataFileElement::DataFileElement( Clib::ConfigElem& elem )
4✔
680
    : proplist( Core::CPropProfiler::Type::DATAFILEELEMENT )
4✔
681
{
682
  proplist.readRemainingPropertiesAsStrings( elem );
4✔
683
}
4✔
684

685
void DataFileElement::printOn( Clib::StreamWriter& sw ) const
4✔
686
{
687
  proplist.printPropertiesAsStrings( sw );
4✔
688
}
4✔
689

690
void read_datastore_dat()
2✔
691
{
692
  std::string datastorefile = Plib::systemstate.config.world_data_path + "datastore.txt";
2✔
693

694
  if ( !Clib::FileExists( datastorefile ) )
2✔
695
    return;
1✔
696

697
  Clib::ConfigFile cf( datastorefile, "DataFile" );
1✔
698
  Clib::ConfigElem elem;
1✔
699

700
  while ( cf.read( elem ) )
4✔
701
  {
702
    DataStoreFile* dsf = new DataStoreFile( elem );
3✔
703
    auto path = std::filesystem::path( dsf->filename() );
3✔
704
    if ( !std::filesystem::exists( path ) )
3✔
NEW
705
      throw std::runtime_error(
×
NEW
706
          fmt::format( "datafile '{}' does not exist, but should due to 'datastore.txt' entry '{}'",
×
NEW
707
                       dsf->filename(), dsf->descriptor ) );
×
708
    Core::configurationbuffer.datastore[dsf->descriptor] = dsf;
3✔
709
  }
3✔
710
}
2✔
711

712
void write_datastore( Clib::StreamWriter& sw )
4✔
713
{
714
  for ( Core::DataStore::iterator itr = Core::configurationbuffer.datastore.begin();
4✔
715
        itr != Core::configurationbuffer.datastore.end(); ++itr )
10✔
716
  {
717
    DataStoreFile* dsf = ( *itr ).second;
6✔
718

719
    dsf->delversion = dsf->oldversion;
6✔
720
    dsf->oldversion = dsf->version;
6✔
721

722
    if ( dsf->dfcontents.get() && dsf->dfcontents->dirty )
6✔
723
    {
724
      // make a new generation of file and write it.
725
      ++dsf->version;
3✔
726

727
      dsf->save();
3✔
728

729
      dsf->dfcontents->dirty = false;
3✔
730
    }
731

732
    dsf->printOn( sw );
6✔
733
  }
734
}
4✔
735

736
void commit_datastore()
4✔
737
{
738
  for ( Core::DataStore::iterator itr = Core::configurationbuffer.datastore.begin();
4✔
739
        itr != Core::configurationbuffer.datastore.end(); ++itr )
10✔
740
  {
741
    DataStoreFile* dsf = ( *itr ).second;
6✔
742

743
    if ( dsf->delversion != dsf->version && dsf->delversion != dsf->oldversion )
6✔
744
    {
745
      Clib::RemoveFile( dsf->filename( dsf->delversion ) );
3✔
746
    }
747

748
    if ( dsf->unload )
6✔
749
    {
750
      if ( dsf->dfcontents.get() != nullptr )
×
751
      {
752
        if ( dsf->dfcontents->count() == 1 )
×
753
        {
754
          dsf->dfcontents.clear();
×
755
        }
756
      }
757
      dsf->unload = false;
×
758
    }
759
  }
760
}
4✔
761
}  // namespace Module
762
}  // namespace Pol
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc