Leviathan  0.8.0.0
Leviathan game engine
FileSystem.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "FileSystem.h"
3 
4 #ifdef LEVIATHAN_USING_OGRE
5 #include "OgreResourceGroupManager.h"
6 #endif
8 
9 #ifndef ALTERNATIVE_EXCEPTIONS_FATAL
10 #include "Exceptions.h"
11 #endif
12 #include "TimeIncludes.h"
13 
14 #include <fstream>
15 #include <ostream>
16 
17 #include <boost/filesystem.hpp>
18 
19 #ifdef __linux__
20 #include <dirent.h>
21 #include <sys/stat.h>
22 #else
23 #endif
24 #ifdef _WIN32
25 
26 #include "WindowsInclude.h"
27 
28 #endif //_WIN32
29 #include <iosfwd>
30 using namespace Leviathan;
31 using namespace std;
32 // ------------------------------------ //
34 {
35  // set static access //
36  Staticaccess = this;
37  // set default values //
38  CurrentFileExtID = 25;
39 
40  // index creation flags //
41  IsAllIndexed = IsTextureIndexed = IsModelIndexed = IsSoundIndexed = IsScriptIndexed =
42  IsSorted = IsBeingSorted = ShouldSortStop = false;
43 }
44 
46 {
47 
48  // Helps catch errors with tests etc.
49  if(Staticaccess == this)
50  Staticaccess = nullptr;
51 
52  SAFE_DELETE_VECTOR(FileTypes);
53 
54  AllFiles.clear();
55 
56  TextureFiles.clear();
57  ModelFiles.clear();
58  SoundFiles.clear();
59  ScriptFiles.clear();
60 
61  // Clear indexes //
62  IsAllIndexed = false;
63  SAFE_DELETE_VECTOR(AllIndexes);
64 
65  IsTextureIndexed = false;
66  SAFE_DELETE_VECTOR(TextureIndexes);
67 
68  IsModelIndexed = false;
69  SAFE_DELETE_VECTOR(ModelIndexes);
70 
71  IsSoundIndexed = false;
72  SAFE_DELETE_VECTOR(SoundIndexes);
73 
74  IsScriptIndexed = false;
75  SAFE_DELETE_VECTOR(ScriptIndexes);
76 }
77 
79 {
80 
81  return Staticaccess;
82 }
83 
84 string Leviathan::FileSystem::DataFolder = "./Data/";
85 string Leviathan::FileSystem::ModelsFolder = "Models/";
86 string Leviathan::FileSystem::ScriptsFolder = "Scripts/";
87 string Leviathan::FileSystem::ShaderFolder = "Shaders/";
88 string Leviathan::FileSystem::TextureFolder = "Textures/";
89 string Leviathan::FileSystem::MaterialFolder = "Materials/";
90 string Leviathan::FileSystem::FontFolder = "Fonts/";
91 string Leviathan::FileSystem::SoundFolder = "Sound/";
92 
93 FileSystem* Leviathan::FileSystem::Staticaccess = NULL;
94 // ------------------------------------ //
96 {
97 
98  ErrorReporter = errorreport;
99 
100  IsSorted = false;
101 
102  // use find files function on data folder and then save results to appropriate vectors //
103  vector<string> files;
104 #ifdef _WIN32
105  GetFilesInDirectory(files, "./Data/");
106 #else
107  GetFilesInDirectory(files, "./Data");
108 #endif
109 
110  if(files.size() < 1) {
111 
112  ErrorReporter->Error(
113  std::string("FileSystem: SearchFiles: No files inside data folder, "
114  "cannot possibly work"));
115  return false;
116  }
117 
118  // save to appropriate places //
119  for(size_t i = 0; i < files.size(); i++) {
120 
121  // create new object for storing this //
122  auto tmpptr = make_shared<FileDefinitionType>(this, files[i]);
123 
124  if(files[i].find("./Data/Textures/") == 0) {
125 
126  // add to texture files //
127  TextureFiles.push_back((tmpptr));
128 
129  } else if(files[i].find("./Data/Models/") == 0) {
130 
131  // add to texture files //
132  ModelFiles.push_back(tmpptr);
133 
134  } else if(files[i].find("./Data/Sound/") == 0) {
135 
136  // add to texture files //
137  SoundFiles.push_back(tmpptr);
138 
139  } else if(files[i].find("./Data/Scripts/") == 0) {
140 
141  // add to texture files //
142  ScriptFiles.push_back(tmpptr);
143  }
144 
145  // everything should be in AllFiles vector //
146  AllFiles.push_back(tmpptr);
147  }
148  // print some info //
149  ErrorReporter->Info("FileSystem: found " + Convert::ToString(AllFiles.size()) +
150  " files in Data folder with " + Convert::ToString(FileTypes.size()) +
151  " different types of extensions");
152 
153  // sort for quick finding //
154  auto starttime = Time::GetTimeMicro64();
155  CreateIndexesForVecs();
156 
157  auto elapsed = Time::GetTimeMicro64() - starttime;
158 
159  // print info //
160  ErrorReporter->Info("FileSystem: vectors sorted and indexes created, took " +
161  Convert::ToString(elapsed) + " micro seconds");
162 
163  return true;
164 }
165 
167 {
168 
169  // Reset values //
170  CurrentFileExtID = 25;
171  IsSorted = false;
172 
173  SAFE_DELETE_VECTOR(FileTypes);
174 
175  AllFiles.clear();
176 
177  TextureFiles.clear();
178  ModelFiles.clear();
179  SoundFiles.clear();
180  ScriptFiles.clear();
181 
182  // Clear indexes //
183  IsAllIndexed = false;
184  SAFE_DELETE_VECTOR(AllIndexes);
185 
186  IsTextureIndexed = false;
187  SAFE_DELETE_VECTOR(TextureIndexes);
188 
189  IsModelIndexed = false;
190  SAFE_DELETE_VECTOR(ModelIndexes);
191 
192  IsSoundIndexed = false;
193  SAFE_DELETE_VECTOR(SoundIndexes);
194 
195  IsScriptIndexed = false;
196  SAFE_DELETE_VECTOR(ScriptIndexes);
197 
198  // Search again //
199  return Init(ErrorReporter);
200 }
201 // ------------------------------------ //
203 {
204 
205  return (DataFolder);
206 }
207 
209 {
210 
211  return (DataFolder + ModelsFolder);
212 }
213 
215 {
216 
217  return (DataFolder + ScriptsFolder);
218 }
219 
221 {
222 
223  return (DataFolder + ShaderFolder);
224 }
225 
227 {
228 
229  return (DataFolder + TextureFolder);
230 }
231 
233 {
234 
235  return (DataFolder + FontFolder);
236 }
237 
239 {
240 
241  return (DataFolder + SoundFolder);
242 }
243 // ------------------------------------ //
245  FileDefinitionType* file, const vector<int>& Ids)
246 {
247  // check does file contain an extension id that is in the vector //
248  for(size_t i = 0; i < Ids.size(); i++) {
249  if(file->ExtensionID == Ids[i]) {
250  // match found //
251  return true;
252  }
253  }
254  return false;
255 }
256 
257 // ------------------------------------ //
258 #ifdef _WIN32
259 void Leviathan::FileSystem::GetWindowsFolder(wstring& path)
260 {
261  wchar_t winddir[MAX_PATH];
262  if(GetWindowsDirectoryW(winddir, MAX_PATH) > 0)
263  path = winddir;
264  if(path.back() != L'/')
265  path += L'/';
266 }
267 
268 void Leviathan::FileSystem::GetSpecialFolder(wstring& path, int specialtype)
269 {
270  wchar_t directory[MAX_PATH];
271  SHGetSpecialFolderPathW(NULL, directory, specialtype, false);
272  path = directory;
273  if(path.back() != L'/')
274  path += L'/';
275 }
276 #endif
277 // ------------------------------------ //
279 {
280 
281  DataFolder = folder;
282 }
283 
284 void Leviathan::FileSystem::SetModelsFolder(const string& folder)
285 {
286 
287  ModelsFolder = folder;
288 }
289 
290 void Leviathan::FileSystem::SetScriptsFolder(const string& folder)
291 {
292 
293  ScriptsFolder = folder;
294 }
295 
296 void Leviathan::FileSystem::SetShaderFolder(const string& folder)
297 {
298 
299  ShaderFolder = folder;
300 }
301 
302 void Leviathan::FileSystem::SetTextureFolder(const string& folder)
303 {
304 
305  TextureFolder = folder;
306 }
307 // ------------------ File handling ------------------ //
308 DLLEXPORT bool FileSystem::LoadDataDump(const string& file,
309  vector<shared_ptr<NamedVariableList>>& vec, LErrorReporter* errorreport)
310 {
311  // Get data //
312  ifstream stream(file);
313 
314  if(!stream.good()) {
315  // no file ! //
316  errorreport->Error("FileSystem: LoadDataDump: Failed to read file: " + file);
317  return false;
318  }
319 
320  // count length //
321  stream.seekg(0, ios::end);
322  auto length = stream.tellg();
323  stream.seekg(0, ios::beg);
324 
325  if(length == std::streampos(0)) {
326 
327  // empty file ! //
328  return false;
329  }
330 
331  // TODO: directly copy into the string
332  unique_ptr<char[]> Buff(new char[(size_t)length + 1]);
333 
334  // set null terminator, just in case
335  (Buff.get())[length] = '\0';
336 
337  stream.read(Buff.get(), length);
338 
339  stream.close();
340 
341  string filecontents = Buff.get();
342 
343  // Create values //
344  return NamedVariableList::ProcessDataDump(filecontents, vec, errorreport);
345 }
346 
347 #ifdef _WIN32
348 DLLEXPORT bool Leviathan::FileSystem::GetFilesInDirectory(vector<string>& files,
349  const string& dirpath, const string& pattern, bool recursive /*= true*/)
350 {
351  string FilePath;
352  string Pattern;
353  HANDLE hFile;
354  WIN32_FIND_DATAA FileInfo;
355 
356  Pattern = dirpath + pattern;
357 
358  hFile = ::FindFirstFileA(Pattern.c_str(), &FileInfo);
359  if(hFile != INVALID_HANDLE_VALUE) {
360  do {
361 
362  if(FileInfo.cFileName[0] != '.') {
363  FilePath.erase();
364  FilePath = dirpath + FileInfo.cFileName + "/";
365 
366  if(FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
367 
368  if(recursive) {
369  // call self to search subdirectory
370  int retr = GetFilesInDirectory(files, FilePath, pattern, recursive);
371  if(!retr)
372  break; // failed //
373  }
374  } else {
375  // save file
376  files.push_back(dirpath + FileInfo.cFileName);
377  }
378  }
379  } while(::FindNextFileA(hFile, &FileInfo) == 1);
380 
381  // close handle //
382  FindClose(hFile);
383  }
384 
385  return true;
386 }
387 #else
389  const string& dirpath, const string& pattern /*= "*.*"*/, bool recursive /*= true*/)
390 {
391  dirent* ent;
392  struct stat st;
393 
394  // Start searching //
395  DIR* dir = opendir(dirpath.c_str());
396 
397  if(!dir) {
398 
399  // Non-existant directory
400  return false;
401  }
402 
403  while((ent = readdir(dir)) != NULL) {
404  const string file_name = ent->d_name;
405 
406  // Ignore if starts with a '.' //
407  if(file_name[0] == '.')
408  continue;
409 
410  const string full_file_name = dirpath + "/" + file_name;
411 
412  // Get info to determine if it is a dirpath //
413  if(stat(full_file_name.c_str(), &st) == -1)
414  continue;
415 
416  // Check if it is a dirpath //
417  if((st.st_mode & S_IFDIR) != 0) {
418  // Go into dirpath if recursive search //
419  if(recursive) {
420  // \todo fix performance //
421  GetFilesInDirectory(files, full_file_name, pattern, recursive);
422  }
423  continue;
424  }
425 
426  files.push_back(full_file_name);
427  }
428 
429  closedir(dir);
430 
431  return true;
432 }
433 #endif
434 // ------------------ File operations ------------------ //
435 size_t Leviathan::FileSystem::GetFileLength(const string& name)
436 {
437 
438  ifstream file(name, ios::binary);
439 
440  if(file.good()) {
441 
442  file.seekg(0, ios::end);
443  auto returnval = file.tellg();
444  file.close();
445  return returnval;
446  }
447 
448 #ifndef ALTERNATIVE_EXCEPTIONS_FATAL
449  throw InvalidArgument("Cannot determine file size it doesn't exist");
450 #else
451  return 0;
452 #endif
453 }
454 
456 {
457 
458  return boost::filesystem::exists(name);
459 }
460 
461 bool Leviathan::FileSystem::WriteToFile(const string& data, const string& filename)
462 {
463  ofstream file(filename, ios::binary);
464  if(file.is_open()) {
465 
466  file << data;
467 
468  file.close();
469  return true;
470  }
471 
472  file.close();
473  return false;
474 }
475 
476 bool Leviathan::FileSystem::WriteToFile(const wstring& data, const wstring& filename)
477 {
478 #ifdef _WIN32
479  wofstream file(filename, ios::binary);
480 #else
481  wofstream file(Convert::Utf16ToUtf8(filename), ios::binary);
482 #endif
483  if(file.is_open()) {
484  file << data;
485 
486  file.close();
487  return true;
488  }
489 
490  file.close();
491  return false;
492 }
493 
494 bool Leviathan::FileSystem::AppendToFile(const string& data, const string& filepath)
495 {
496 
497  ofstream file(filepath, ofstream::app | ios::binary);
498 
499  if(file.is_open()) {
500 
501  file << data;
502 
503  file.close();
504  return true;
505  }
506 
507  file.close();
508  return false;
509 }
510 
512  const wstring& file, wstring& resultreceiver)
513 {
514 #ifdef _WIN32
515  wifstream reader(file, ios::in | ios::binary);
516 #else
517  wifstream reader(Convert::Utf16ToUtf8(file), ios::in | ios::binary);
518 #endif
519  if(reader) {
520 
521  // go to end to count length //
522  reader.seekg(0, ios::end);
523 
524  streamoff rpos = reader.tellg();
525 
526  // cannot be loaded //
527  LEVIATHAN_ASSERT(std::numeric_limits<streamoff>::max() >= rpos, "file is too large");
528 
529  resultreceiver.resize(static_cast<size_t>(rpos));
530  // back to start //
531  reader.seekg(0, ios::beg);
532  // read the actual data //
533  reader.read(&resultreceiver[0], resultreceiver.size());
534 
535  // done, cleanup //
536  reader.close();
537  return true;
538  }
539 
540  return false;
541 }
542 
544  const string& file, string& resultreceiver)
545 {
546 
547  ifstream reader(file, ios::in | ios::binary);
548 
549  if(reader) {
550 
551  // go to end to count length //
552  reader.seekg(0, ios::end);
553 
554  streamoff rpos = reader.tellg();
555 
556 
557  // cannot be loaded //
558  LEVIATHAN_ASSERT(std::numeric_limits<streamoff>::max() >= rpos, "file is too large");
559 
560  resultreceiver.resize(static_cast<size_t>(rpos));
561  // back to start //
562  reader.seekg(0, ios::beg);
563  // read the actual data //
564  reader.read(&resultreceiver[0], resultreceiver.size());
565 
566  // done, cleanup //
567  reader.close();
568  return true;
569  }
570 
571  return false;
572 }
573 // ------------------ Non static part ------------------ //
575 {
576  // check if already sorted //
577  if(IsSorted)
578  return;
579 
580  ShouldSortStop = false;
581  // call sort on the vectors //
582  IsBeingSorted = true;
583 
584  // looping so that other thread can cancel the action before it is finished //
585  for(int i = 0; i < 5; i++) {
586  // switch on index and call std sort //
587  switch(i) {
588  case 0: sort(AllFiles.begin(), AllFiles.end(), FileDefSorter()); break;
589  case 1: sort(TextureFiles.begin(), TextureFiles.end(), FileDefSorter()); break;
590  case 2: sort(ModelFiles.begin(), ModelFiles.end(), FileDefSorter()); break;
591  case 3: sort(SoundFiles.begin(), SoundFiles.end(), FileDefSorter()); break;
592  case 4: sort(ScriptFiles.begin(), ScriptFiles.end(), FileDefSorter()); break;
593  }
594 
595  // check for end
596  if(ShouldSortStop) {
597  // asked to stop //
598  goto end;
599  }
600  }
601  // sort done
602  IsSorted = true;
603 
604 end:
605  IsBeingSorted = false;
606 }
607 
608 DLLEXPORT void Leviathan::FileSystem::CreateIndexesForVecs(bool forcerecreation /*= false*/)
609 {
610  // check are vectors sorted, if not call sort //
611  if(!IsSorted) {
612 
613  SortFileVectors();
614  }
615 
616  _CreateIndexesIfMissing(AllFiles, AllIndexes, IsAllIndexed, forcerecreation);
617  _CreateIndexesIfMissing(TextureFiles, TextureIndexes, IsTextureIndexed, forcerecreation);
618  _CreateIndexesIfMissing(ModelFiles, ModelIndexes, IsModelIndexed, forcerecreation);
619  _CreateIndexesIfMissing(SoundFiles, SoundIndexes, IsSoundIndexed, forcerecreation);
620  _CreateIndexesIfMissing(ScriptFiles, ScriptIndexes, IsScriptIndexed, forcerecreation);
621 }
622 // ------------------------------------ //
624 {
625  // check does it exist //
626  for(size_t i = 0; i < FileTypes.size(); i++) {
627  if(StringOperations::CompareInsensitive(FileTypes[i]->Name, extension))
628  return FileTypes[i]->ID;
629  }
630 
631  // add //
632  CurrentFileExtID++;
633  FileTypes.push_back(new FileTypeHolder(CurrentFileExtID, extension));
634 
635  return CurrentFileExtID;
636 }
637 
638 void Leviathan::FileSystem::GetExtensionIDS(const string& extensions, vector<int>& ids)
639 {
640  // generate info about the extensions //
641  vector<string> Exts;
642  StringOperations::CutString(extensions, string("|"), Exts);
643  if(Exts.size() == 0) {
644  // just one extension //
645  ids.push_back(RegisterExtension(extensions));
646  return;
647  }
648 
649  for(size_t i = 0; i < Exts.size(); i++) {
650  ids.push_back(RegisterExtension(Exts[i]));
651  }
652 }
653 
655 {
656  // Look for it //
657  for(size_t i = 0; i < FileTypes.size(); i++) {
658  if(FileTypes[i]->ID == id)
659  return FileTypes[i]->Name;
660  }
661 
662  // Not found //
663 #ifndef ALTERNATIVE_EXCEPTIONS_FATAL
664  throw NotFound("No extension corresponds with id");
665 #else
666  LEVIATHAN_ASSERT(0, "No extension corresponds with id");
667  return FileTypes[0]->Name;
668 #endif // ALTERNATIVE_EXCEPTIONS_FATAL
669 }
670 // ------------------------------------ //
672  FILEGROUP which, const string& name, const string& extensions, bool searchall /*= true*/)
673 {
674  if(name.empty())
675  return "";
676 
677  // generate info about the search file //
678  vector<int> ExtensionIDS;
679  GetExtensionIDS(extensions, ExtensionIDS);
680 
681  switch(which) {
682  case FILEGROUP_MODEL: {
683  shared_ptr<FileDefinitionType> result =
684  _SearchForFileInVec(ModelFiles, ExtensionIDS, name, IsModelIndexed, &ModelIndexes);
685  if(result.get() != NULL) {
686  // found //
687  return result.get()->RelativePath;
688  }
689  } break;
690  case FILEGROUP_TEXTURE: {
691  shared_ptr<FileDefinitionType> result = _SearchForFileInVec(
692  TextureFiles, ExtensionIDS, name, IsTextureIndexed, &TextureIndexes);
693 
694  if(result.get() != NULL) {
695  // found //
696  return result.get()->RelativePath;
697  }
698  } break;
699  case FILEGROUP_SOUND: {
700  shared_ptr<FileDefinitionType> result =
701  _SearchForFileInVec(SoundFiles, ExtensionIDS, name, IsSoundIndexed, &SoundIndexes);
702  if(result.get() != NULL) {
703  // found //
704  return result.get()->RelativePath;
705  }
706  } break;
707  case FILEGROUP_SCRIPT: {
708  shared_ptr<FileDefinitionType> result = _SearchForFileInVec(
709  ScriptFiles, ExtensionIDS, name, IsScriptIndexed, &ScriptIndexes);
710  if(result.get() != NULL) {
711  // found //
712  return result.get()->RelativePath;
713  }
714  } break;
715  case FILEGROUP_OTHER: {
716  shared_ptr<FileDefinitionType> result =
717  _SearchForFileInVec(AllFiles, ExtensionIDS, name, IsAllIndexed, &AllIndexes);
718  if(result.get() != NULL) {
719  // found //
720  return result.get()->RelativePath;
721  }
722  } break;
723  }
724 
725 
726  // still not found, if searchall specified search all files vector //
727  if(searchall) {
728  shared_ptr<FileDefinitionType> result =
729  _SearchForFileInVec(AllFiles, ExtensionIDS, name, IsAllIndexed, &AllIndexes);
730  if(result.get() != NULL) {
731  // found //
732  return result.get()->RelativePath;
733  }
734  }
735  // not found return empty and if debug build warn //
736 
737  ErrorReporter->Error("FileSystem: File not found: " + name + "." + extensions);
738 
739  return "";
740 }
741 
742 DLLEXPORT vector<shared_ptr<FileDefinitionType>> Leviathan::FileSystem::FindAllMatchingFiles(
743  FILEGROUP which, const string& regexname, const string& extensions,
744  bool searchall /*= true*/)
745 {
746  // generate info about the search file //
747  vector<int> ExtensionIDS;
748  GetExtensionIDS(extensions, ExtensionIDS);
749 
750  // create regex //
751  regex usedregex(regexname, regex_constants::ECMAScript | regex_constants::icase);
752 
753  vector<shared_ptr<FileDefinitionType>> foundfiles;
754 
755  if(searchall) {
756 
757  _SearchForFilesInVec(AllFiles, foundfiles, ExtensionIDS, usedregex);
758 
759  } else {
760  // specific vector //
761  vector<shared_ptr<FileDefinitionType>>* targetvector = NULL;
762 
763  switch(which) {
764  case FILEGROUP_MODEL: {
765  targetvector = &ModelFiles;
766  } break;
767  case FILEGROUP_TEXTURE: {
768  targetvector = &TextureFiles;
769  } break;
770  case FILEGROUP_SOUND: {
771  targetvector = &SoundFiles;
772  } break;
773  case FILEGROUP_SCRIPT: {
774  targetvector = &ScriptFiles;
775  } break;
776  case FILEGROUP_OTHER: {
777  targetvector = &AllFiles;
778  } break;
779  }
780 
781  _SearchForFilesInVec(*targetvector, foundfiles, ExtensionIDS, usedregex);
782  }
783 
784  // return what we found //
785  return foundfiles;
786 }
787 
788 
789 // ------------------------------------ //
790 vector<shared_ptr<FileDefinitionType>>& Leviathan::FileSystem::GetModelFiles()
791 {
792  return ModelFiles;
793 }
794 
795 vector<shared_ptr<FileDefinitionType>>& Leviathan::FileSystem::GetSoundFiles()
796 {
797  return SoundFiles;
798 }
799 
800 vector<shared_ptr<FileDefinitionType>>& Leviathan::FileSystem::GetAllFiles()
801 {
802  return AllFiles;
803 }
804 
805 vector<shared_ptr<FileDefinitionType>>& Leviathan::FileSystem::GetScriptFiles()
806 {
807  return ScriptFiles;
808 }
809 // ------------------------------------ //
810 shared_ptr<FileDefinitionType> Leviathan::FileSystem::_SearchForFileInVec(
811  vector<shared_ptr<FileDefinitionType>>& vec, vector<int>& extensions, const string& name,
812  bool UseIndexVector, vector<CharWithIndex*>* Index)
813 {
814  size_t StartSpot = 0;
815 
816  // use index to get start spot for faster searching //
817  if(UseIndexVector) {
818  char startchar = name[0];
819  bool Found = false;
820 
821  // find matching char //
822  for(unsigned int i = 0; i < Index->size(); i++) {
823  if(Index->at(i)->Char == startchar) {
824  Found = true;
825  StartSpot = Index->at(i)->Index;
826  break;
827  }
828  }
829  // if character that starts the word wasn't found it can't be there, exit function //
830  if(!Found)
831  return NULL;
832  }
833 
834  for(size_t i = StartSpot; i < vec.size(); i++) {
835  // if no extension specified skip checking them //
836  if(extensions.size() > 0) {
837  // check does extension(s) match //
838  if(!DoesExtensionMatch(vec[i].get(), extensions))
839  continue;
840  }
841  // extensions match check name //
842  if((vec[i]->Name != name))
843  continue;
844 
845  // match //
846  return vec[i];
847  }
848  // nothing //
849  return NULL;
850 }
851 
852 void Leviathan::FileSystem::_SearchForFilesInVec(vector<shared_ptr<FileDefinitionType>>& vec,
853  vector<shared_ptr<FileDefinitionType>>& results, vector<int>& extensions,
854  const regex& regex)
855 {
856  for(size_t i = 0; i < vec.size(); i++) {
857  // if no extension specified skip checking them //
858  if(extensions.size() > 0) {
859  // check does extension(s) match //
860  if(!DoesExtensionMatch(vec[i].get(), extensions)) {
861  continue;
862  }
863  }
864  // extensions match check name //
865  if(!regex_match(vec[i]->Name, regex)) {
866  continue;
867  }
868 
869  // match //
870  results.push_back(vec[i]);
871  }
872 }
873 
874 void Leviathan::FileSystem::_CreateIndexesIfMissing(
875  vector<shared_ptr<FileDefinitionType>>& vec, vector<CharWithIndex*>& resultvec,
876  bool& indexed, const bool& force /*= false*/)
877 {
878  // we'll need to delete old ones if index creation is forced //
879  if(force) {
880  indexed = false;
881  SAFE_DELETE_VECTOR(resultvec);
882  }
883  // if they are valid we can just return //
884  if(indexed)
885  return;
886 
887  // now that the file vector is sorted we can loop through it and every time first character
888  // changes add it to index
889  char curchar = '!';
890 
891  for(size_t i = 0; i < vec.size(); i++) {
892  if(vec[i]->Name[0] != curchar) {
893  // beginning character changed, push to indexes //
894  curchar = vec[i]->Name[0];
895  resultvec.push_back(new CharWithIndex(curchar, i));
896  }
897  }
898 
899  // done //
900  indexed = true;
901 }
902 
903 #ifdef LEVIATHAN_USING_OGRE
904 
906 void RegisterSubFolders(Ogre::ResourceGroupManager& manager, const std::string& groupname,
907  const Ogre::String& basefolder)
908 {
909  if(!boost::filesystem::is_directory(basefolder)) {
910  LOG_ERROR("FileSystem: register folder doesn't exist: " + basefolder);
911  return;
912  }
913 
914  manager.addResourceLocation(basefolder, "FileSystem", "LeviathanInternal");
915 
916  boost::filesystem::recursive_directory_iterator dir{boost::filesystem::path(basefolder)};
917 
918  for(const auto& i : dir) {
919  if(boost::filesystem::is_directory(i)) {
920 
921  manager.addResourceLocation(i.path().string(), "FileSystem", "LeviathanInternal");
922  }
923  }
924 }
925 
926 bool RegisterIfExists(Ogre::ResourceGroupManager& manager, const std::string& groupname,
927  const Ogre::String& basefolder)
928 {
929  if(boost::filesystem::exists(basefolder)) {
930  RegisterSubFolders(manager, groupname, basefolder);
931  return true;
932  }
933 
934  return false;
935 }
936 
938 {
939  // get the resource managing singleton //
940  Ogre::ResourceGroupManager& manager = Ogre::ResourceGroupManager::getSingleton();
941 
942  // Internal resources
943  manager.createResourceGroup("LeviathanInternal");
944  RegisterSubFolders(manager, "LeviathanInternal", "CoreOgreScripts");
945 
946  // All generated stuff can be dumped here
947  manager.createResourceGroup("Generated");
948 
949 
950  // Models folder //
951  manager.createResourceGroup("MainModelsFolder");
952  RegisterSubFolders(manager, "MainModelsFolder", DataFolder + ModelsFolder);
953 
954  // Textures folder //
955  manager.createResourceGroup("MainTexturesFolder");
956  RegisterSubFolders(manager, "MainTexturesFolder", DataFolder + TextureFolder);
957 
958  // Materials folder //
959  manager.createResourceGroup("MainMaterialsFolder");
960  RegisterSubFolders(manager, "MainMaterialsFolder", DataFolder + MaterialFolder);
961 
962  // Scripts folder //
963 
964  // Only one of these is registered
965  if(!RegisterIfExists(manager, "GuiScripts", DataFolder + ScriptsFolder + "GUI")) {
966  RegisterIfExists(manager, "GuiScripts", DataFolder + ScriptsFolder + "gui");
967  }
968 
969  // shaders //
970  manager.createResourceGroup("ShadersFolder");
971  RegisterSubFolders(manager, "ShadersFolder", DataFolder + ShaderFolder);
972 
973  // // Terrain group //
974  // manager.createResourceGroup("Terrain");
975 
976  // folder = DataFolder+"Cache/Terrain/";
977 
978  // manager.addResourceLocation(folder, "FileSystem", "Terrain", true, false);
979 
980  // // add cache to general //
981  // folder = DataFolder+"Cache/";
982  // manager.addResourceLocation(folder, "FileSystem", "General");
983 
984 
985  // Fonts group //
986  manager.createResourceGroup("Fonts");
987  RegisterSubFolders(manager, "Fonts", DataFolder + FontFolder);
988 
989  // possibly register addon folders //
990 
991 
992  // initialize the groups //
993  if(testload) {
994 
995  LOG_INFO("FileSystem: RegisterOGREResourceGroups: doing test load, skipping parsing");
996 
997  } else {
998 
999  manager.initialiseAllResourceGroups(true);
1000  }
1001 
1002  // load the groups //
1003  // manager.loadResourceGroup("MainModelsFolder");
1004 }
1005 
1007 {
1008 
1009  Ogre::ResourceGroupManager& manager = Ogre::ResourceGroupManager::getSingleton();
1010 
1011  Ogre::String groupname = location + "_group";
1012 
1013  // check does it exist //
1014  auto groups = manager.getResourceGroups();
1015 
1016  for(size_t i = 0; i < groups.size(); i++) {
1017  if(groups[i] == groupname)
1018  return;
1019  }
1020 
1021  manager.createResourceGroup(groupname);
1022 
1023  manager.addResourceLocation(location, "FileSystem", groupname, true);
1024 
1025  manager.initialiseResourceGroup(groupname, true);
1026 }
1027 #endif // LEVIATHAN_USING_OGRE
1028 // ------------------ FileDefinitionType ------------------ //
1030  RelativePath(path)
1031 {
1032  // get extension //
1033  string tempexpt = StringOperations::GetExtension<std::string>(path);
1034 
1035  // register extension and store id //
1036  ExtensionID = instance->RegisterExtension(tempexpt);
1037 
1038  // save name //
1039  Name = StringOperations::RemoveExtension<std::string>(path, true);
1040 }
1041 
1043 {
1044  return this->Name < other.Name;
1045 }
1046 
1048 
1050 {
1051  // Add the extension text to the end of the name //
1052  return Name + "." + FileSystem::Get()->GetExtensionName(ExtensionID);
1053 }
1054 // ------------------ FileDefSorter ------------------ //
1055 bool Leviathan::FileDefSorter::operator()(const std::shared_ptr<FileDefinitionType>& first,
1056  const std::shared_ptr<FileDefinitionType>& second)
1057 {
1058  return (*first.get()) < *(second).get();
1059 }
1060 // ------------------ CharWithIndex ------------------ //
1062 {
1063  Char = L' ';
1064  Index = -1;
1065 }
1066 
1067 CharWithIndex::CharWithIndex(char character, size_t index) : Char(character), Index(index) {}
1068 // ------------------ FileTypeHolder ------------------ //
1069 FileTypeHolder::FileTypeHolder(int id, const std::string& name) : ID(id), Name(name) {}
static DLLEXPORT std::string GetScriptsFolder()
Definition: FileSystem.cpp:214
DLLEXPORT void SortFileVectors()
Definition: FileSystem.cpp:574
static DLLEXPORT std::string GetModelsFolder()
Definition: FileSystem.cpp:208
static DLLEXPORT std::string GetDataFolder()
Definition: FileSystem.cpp:202
static DLLEXPORT void SetModelsFolder(const std::string &folder)
Definition: FileSystem.cpp:284
FileDefinitionType(FileSystem *instance, const std::string &path)
static DLLEXPORT bool ProcessDataDump(const std::string &data, std::vector< std::shared_ptr< NamedVariableList >> &vec, LErrorReporter *errorreport, std::map< std::string, std::shared_ptr< VariableBlock >> *predefined=nullptr)
Definition: NamedVars.cpp:612
bool RegisterIfExists(Ogre::ResourceGroupManager &manager, const std::string &groupname, const Ogre::String &basefolder)
Definition: FileSystem.cpp:926
DLLEXPORT std::vector< std::shared_ptr< FileDefinitionType > > FindAllMatchingFiles(FILEGROUP which, const std::string &regexname, const std::string &extensions, bool searchall=true)
Returns all matching files.
Definition: FileSystem.cpp:742
static DLLEXPORT void SetDataFolder(const std::string &folder)
Definition: FileSystem.cpp:278
#define LOG_INFO(x)
Definition: Define.h:81
DLLEXPORT std::vector< std::shared_ptr< FileDefinitionType > > & GetModelFiles()
Definition: FileSystem.cpp:790
#define LOG_ERROR(x)
Definition: Define.h:83
DLLEXPORT bool ReSearchFiles()
Destroys the current index and recreates it.
Definition: FileSystem.cpp:166
static DLLEXPORT bool AppendToFile(const std::string &data, const std::string &filepath)
Definition: FileSystem.cpp:494
static DLLEXPORT std::string Utf16ToUtf8(const std::wstring &utf16str)
Encodes an UTF8 string from a wide string (wstring/utf16)
Definition: Convert.cpp:108
void RegisterSubFolders(Ogre::ResourceGroupManager &manager, const std::string &groupname, const Ogre::String &basefolder)
Ogre recursive resource groups don&#39;t work so we hack around it with this.
Definition: FileSystem.cpp:906
Class for indexing and searching game data directory.
Definition: FileSystem.h:65
STL namespace.
static DLLEXPORT void RegisterOGREResourceLocation(const std::string &location)
static DLLEXPORT bool GetFilesInDirectory(std::vector< std::string > &files, const std::string &dirpath, const std::string &pattern="*.*", bool recursive=true)
Definition: FileSystem.cpp:388
static DLLEXPORT std::string GetShaderFolder()
Definition: FileSystem.cpp:220
FileTypeHolder(int id, const std::string &name)
DLLEXPORT void GetExtensionIDS(const std::string &extensions, std::vector< int > &ids)
Returns list of matching ids to the extensions.
Definition: FileSystem.cpp:638
static DLLEXPORT bool DoesExtensionMatch(FileDefinitionType *file, const std::vector< int > &Ids)
Definition: FileSystem.cpp:244
#define SAFE_DELETE_VECTOR(x)
Definition: Define.h:123
DLLEXPORT bool operator()(const std::shared_ptr< FileDefinitionType > &first, const std::shared_ptr< FileDefinitionType > &second)
DLLEXPORT void CreateIndexesForVecs(bool forcerecreation=false)
Definition: FileSystem.cpp:608
static DLLEXPORT int64_t GetTimeMicro64()
static DLLEXPORT FileSystem * Get()
Definition: FileSystem.cpp:78
static DLLEXPORT void SetScriptsFolder(const std::string &folder)
Definition: FileSystem.cpp:290
static DLLEXPORT void SetTextureFolder(const std::string &folder)
Definition: FileSystem.cpp:302
static DLLEXPORT void SetShaderFolder(const std::string &folder)
Definition: FileSystem.cpp:296
static DLLEXPORT std::string GetFontFolder()
Definition: FileSystem.cpp:232
DLLEXPORT ~FileSystem()
Definition: FileSystem.cpp:45
DLLEXPORT std::vector< std::shared_ptr< FileDefinitionType > > & GetAllFiles()
Definition: FileSystem.cpp:800
DLLEXPORT bool Init(LErrorReporter *errorreport)
Runs the indexing and sorting.
Definition: FileSystem.cpp:95
std::string GetNameWithExtension() const
DLLEXPORT std::vector< std::shared_ptr< FileDefinitionType > > & GetScriptFiles()
Definition: FileSystem.cpp:805
static std::string ToString(const T &val)
Definition: Convert.h:72
DLLEXPORT FileSystem()
Definition: FileSystem.cpp:33
static DLLEXPORT bool FileExists(const std::string &name)
Definition: FileSystem.cpp:455
DLLEXPORT std::string SearchForFile(FILEGROUP which, const std::string &name, const std::string &extensions, bool searchall=true)
Searches for a file.
Definition: FileSystem.cpp:671
static bool CompareInsensitive(const StringTypeN &data, const StringTypeN &second)
static DLLEXPORT std::string GetSoundFolder()
Definition: FileSystem.cpp:238
DLLEXPORT std::vector< std::shared_ptr< FileDefinitionType > > & GetSoundFiles()
Definition: FileSystem.cpp:795
virtual void Error(const std::string &Text)=0
Helper class for indexing.
Definition: FileSystem.h:24
static DLLEXPORT bool ReadFileEntirely(const std::string &file, std::string &resultreceiver)
Definition: FileSystem.cpp:543
static DLLEXPORT bool LoadDataDump(const std::string &file, std::vector< std::shared_ptr< NamedVariableList >> &vec, LErrorReporter *errorreport)
Definition: FileSystem.cpp:308
static DLLEXPORT std::string GetTextureFolder()
Definition: FileSystem.cpp:226
#define DLLEXPORT
Definition: Include.h:115
static bool CutString(const StringTypeN &strtocut, const StringTypeN &separator, std::vector< StringTypeN > &vec)
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
static DLLEXPORT size_t GetFileLength(const std::string &name)
Definition: FileSystem.cpp:435
static DLLEXPORT void RegisterOGREResourceGroups(bool testload=false)
Definition: FileSystem.cpp:937
DLLEXPORT int RegisterExtension(const std::string &extension)
Reserves a number for an extension string.
Definition: FileSystem.cpp:623
static DLLEXPORT bool WriteToFile(const std::string &data, const std::string &filename)
Definition: FileSystem.cpp:461
bool operator<(const FileDefinitionType &other) const
DLLEXPORT const std::string & GetExtensionName(int id) const
Retrieves the name of the extension from the id.
Definition: FileSystem.cpp:654