Harmonic Flow Framework (libhffwk)
Cross platform C++ 2D Game Engine Framework
PakInterface.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 */
21 #include "PakInterface.h"
22 
23 // Windows specific
24 #if defined(HF_PLATFORM_WINDOWS)
25 #include <direct.h>
26 // Mac + Linux + iOS + Android
27 #elif defined(HF_PAK_USE_MMAP)
28 #include <unistd.h>
29 #include <string.h>
30 #else
31 #error "Implement!"
32 #endif
33 #include <assert.h>
34 #include "util/StringUtil.h"
35 #include "Environment.h"
36 
37 #include "debug/CrtDbgNew.h"
38 
39 enum
40 {
41  FILEFLAGS_END = 0x80
42 };
43 
44 // Windows
45 #if defined(HF_PLATFORM_WINDOWS)
46 static HANDLE gPakFileMapping = NULL;
47 #endif
48 
49 using namespace HFCore;
50 
52 PakInterfaceBase **gPakInterfaceP = NULL;
53 
55 {
56  mFileDirUtils = fileDirUtils;
57  assert(mFileDirUtils != NULL);
58 
59  // Windows specific
60 #if defined(HF_PLATFORM_WINDOWS)
61  if (getPakPtr() == NULL)
62  *gPakInterfaceP = this;
63 #endif
64 
65 #if defined(HF_PLATFORM_ANDROID)
66  // cache HFActivity class for later usage:
67  mEnv = Android_JNI_GetEnv();
68  assert(mEnv != NULL);
69 
70  // Get android java class path:
71  UString androidClassPath = HFCORE_ENV->getAndroidActivityClass();
72  assert(androidClassPath.length() > 0);
73  __android_log_print(ANDROID_LOG_INFO, "HFCore.engineLog",
74  "Android activity class path is: %s.\r\n",
75  androidClassPath.toUtf8());
76 
77  jclass localClass = mEnv->FindClass(androidClassPath.toUtf8());
78  mActivityClass = reinterpret_cast<jclass>(mEnv->NewGlobalRef(localClass));
79  assert(mActivityClass);
80 #endif
81 }
82 
84 {
85  // remove file mapping:
86  PakCollectionList::iterator pakCollList = mPakCollectionList.begin();
87  while (pakCollList != mPakCollectionList.end())
88  {
89 #if defined(HF_PLATFORM_WINDOWS)
90  CloseHandle(pakCollList->mMappingHandle);
91  CloseHandle(pakCollList->mFileHandle);
92 #elif defined(HF_PAK_USE_MMAP)
93  munmap(pakCollList->mDataPtr, pakCollList->mFileSize);
94  close(pakCollList->mFileHandle);
95 #else
96 #error "Implement!"
97 #endif
98  pakCollList++;
99  }
100 
101  PakRecordMap::iterator itr = mPakRecordMap.begin();
102  while (itr != mPakRecordMap.end())
103  {
104  HF_SAFE_DELETE(itr->second);
105  ++itr;
106  }
107 
108 #if defined(HF_PLATFORM_ANDROID)
109  if (mActivityClass)
110  {
111  mEnv->DeleteGlobalRef(mActivityClass);
112  }
113 #endif
114 }
115 
116 bool PakInterface::addPakFile(const std::string &fileName,
117  const std::string &decryptPassword)
118 {
119  int32_hf startPos = 0;
120  int32_hf fileSize = 0;
121 
122  // get hash for the password:
123  mPasswordHash = getASCIISum(decryptPassword);
124 
125  // Windows specific
126 #if defined(HF_PLATFORM_WINDOWS)
127  std::wstring fileNameW = StringUtil::StringToWString(fileName);
128  HANDLE fileHandle = CreateFileW(fileNameW.c_str(), GENERIC_READ,
129  FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
130 
131  if (fileHandle == INVALID_HANDLE_VALUE)
132  return false;
133 
134  fileSize = GetFileSize(fileHandle, 0);
135 
136  HANDLE fileMapping = CreateFileMapping(fileHandle, NULL, PAGE_READONLY, 0, fileSize, NULL);
137  if (fileMapping == NULL)
138  {
139  CloseHandle(fileHandle);
140  return false;
141  }
142 
143  void *ptr = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, fileSize);
144  if (ptr == NULL)
145  {
146  CloseHandle(fileMapping);
147  CloseHandle(fileHandle);
148  return false;
149  }
150 
151  mPakCollectionList.push_back(PakCollection());
152  PakCollection *pakCollection = &mPakCollectionList.back();
153 
154  pakCollection->mFileHandle = fileHandle;
155  pakCollection->mMappingHandle = fileMapping;
156  pakCollection->mDataPtr = ptr;
157  pakCollection->mFileSize = fileSize;
158  pakCollection->mDecryptPassword = decryptPassword;
159 
160  // Mac + Linux + iOS + Android
161 #elif defined(HF_PAK_USE_MMAP)
162  int32_hf fd;
163  void *ptr;
164  struct stat sbuf;
165 
166  // On Android we need to get fileDescriptor through AssetManager:
167 #if defined(HF_PLATFORM_ANDROID)
168  int32_hf tmpStart = 0;
169  fd = JNI_openFD(fileName, &tmpStart, &fileSize);
170  startPos = tmpStart;
171 
172  __android_log_print(ANDROID_LOG_INFO, "HFCore.engineLog",
173  "JNI_openFD(%s) fd [%d] start [%d] length [%d] OK.\r\n",
174  fileName.c_str(), fd, tmpStart, fileSize);
175 
176  if (fstat(fd, &sbuf) == -1)
177  {
178  __android_log_print(ANDROID_LOG_INFO, "HFCore.engineLog",
179  "fstat(fd, &sbuf) failed.\r\n");
180  return false;
181  }
182 #else
183  int8_hf *tmpUtf8 = mFileDirUtils->makeFilePath((int8_hf *)fileName.c_str());
184  if ((fd = open(tmpUtf8, O_RDONLY)) == -1)
185  {
186  return false;
187  }
188 
189  if (stat(tmpUtf8, &sbuf) == -1)
190  {
191  return false;
192  }
193  fileSize = (int32_hf)sbuf.st_size;
194 #endif
195  ptr = mmap((caddr_t)0, (int32_hf)sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
196  if (ptr == MAP_FAILED)
197  {
198  return false;
199  }
200 
201  mPakCollectionList.push_back(PakCollection());
202  PakCollection *pakCollection = &mPakCollectionList.back();
203 
204  pakCollection->mFileHandle = fd;
205  pakCollection->mDataPtr = ptr;
206  pakCollection->mFileSize = fileSize;
207  pakCollection->mDecryptPassword = decryptPassword;
208 #else
209 #error "Implement!"
210 #endif
211 
212  PakRecord *pakRecord = new PakRecord();
213  pakRecord->mCollection = pakCollection;
214  pakRecord->mFileName = fileName;
215  pakRecord->mStartPos = startPos;
216  pakRecord->mSize = fileSize;
217  std::string upperName = StringUtil::StringToUpper(fileName);
218  mPakRecordMap.insert(PakRecordMap::value_type(upperName, pakRecord));
219 
220  PFILE *fp = FOpen(fileName.c_str(), "rb");
221  if (fp == NULL)
222  {
223  return false;
224  }
225 
226  uint32_hf magic = 0;
227  FRead(&magic, sizeof(uint32_hf), 1, fp);
228  if (magic != 0xBAC04AC0)
229  {
230  FClose(fp);
231  return false;
232  }
233 
234  uint32_hf version = 0;
235  FRead(&version, sizeof(uint32_hf), 1, fp);
236  if (version > 0)
237  {
238  FClose(fp);
239  return false;
240  }
241 
242  int32_hf pos = startPos;
243 
244  for (;;)
245  {
246  uint8_hf flags = 0;
247  int32_hf count = FRead(&flags, 1, 1, fp);
248  if ((flags & FILEFLAGS_END) || (count == 0))
249  break;
250 
251  uint8_hf nameWidth = 0;
252  int8_hf name[256];
253  FRead(&nameWidth, 1, 1, fp);
254  FRead(name, 1, nameWidth, fp);
255  name[nameWidth] = 0;
256 
257  int32_hf srcSize = 0;
258  FRead(&srcSize, sizeof(int32_hf), 1, fp);
259 
260  std::string upperName = StringUtil::StringToUpper(name);
261  PakRecord *pakRecord = new PakRecord();
262  pakRecord->mCollection = pakCollection;
263  pakRecord->mFileName = name;
264  pakRecord->mStartPos = pos;
265  pakRecord->mSize = srcSize;
266  mPakRecordMap.insert(PakRecordMap::value_type(upperName, pakRecord));
267 
268  pos += srcSize;
269  }
270 
271  int32_hf offset = FTell(fp);
272 
273  // Now fix file starts
274  PakRecordMap::iterator recordItr = mPakRecordMap.begin();
275  while (recordItr != mPakRecordMap.end())
276  {
277  PakRecord *pakRecord = recordItr->second;
278  if (pakRecord->mCollection == pakCollection)
279  pakRecord->mStartPos += offset;
280  ++recordItr;
281  }
282 
283  FClose(fp);
284 
285  return true;
286 }
287 
289 {
290  uint32_hf asciisum = 0;
291 
292  for (uint32_hf i = 0; i < (uint32_hf)s.length(); i++)
293  {
294  asciisum += (uint32_hf)s[i];
295  }
296 
297  return asciisum;
298 }
299 
300 static void fixFileName(const int8_hf *fileName, int8_hf *upperName)
301 {
302  if ((fileName[0] != 0) && (fileName[1] == ':'))
303  {
304  int8_hf dir[256];
305  // Windows
306 #if defined(HF_PLATFORM_WINDOWS)
307  int8_hf *ptr = _getcwd(dir, 256);
308  if (ptr == NULL)
309  {
310  upperName = NULL;
311  return;
312  }
313  // Mac + Linux + iOS + Android
314 #elif defined(HF_PAK_USE_MMAP)
315  int8_hf *ptr = getcwd(dir, 256);
316  if (ptr == NULL)
317  {
318  upperName = NULL;
319  return;
320  }
321 #else
322 #error "Implement!"
323 #endif
324  int32_hf len = strlen(dir);
325  dir[len++] = '/';//'\\';
326  dir[len] = 0;
327 
328  // Windows
329 #if defined(HF_PLATFORM_WINDOWS)
330  if (_strnicmp(dir, fileName, len) == 0)
331  fileName += len;
332  // Mac + Linux + iOS + Android
333 #elif defined(HF_PAK_USE_MMAP)
334  if (strncasecmp(dir, fileName, len) == 0)
335  fileName += len;
336 #else
337 #error "Implement!"
338 #endif
339  }
340 
341  bool lastSlash = false;
342  const int8_hf *src = fileName;
343  int8_hf *dest = upperName;
344 
345  for (;;)
346  {
347  int8_hf c = *(src++);
348 
349  if ((c == '\\') || (c == '/'))
350  {
351  if (!lastSlash)
352  *(dest++) = '/';//'\\';
353  lastSlash = true;
354  }
355  else if ((c == '.') && (lastSlash) && (*src == '.'))
356  {
357  // We have a '/..' on our hands
358  dest--;
359  while ((dest > upperName + 1) && (*(dest - 1) != '\\'))
360  --dest;
361  src++;
362  }
363  else
364  {
365  *(dest++) = toupper((uint8_hf) c);
366  if (c == 0)
367  break;
368  lastSlash = false;
369  }
370  }
371 }
372 
373 PFILE *PakInterface::FOpen(const int8_hf *fileName, const int8_hf *access)
374 {
375  // Windows
376 #if defined(HF_PLATFORM_WINDOWS)
377  if ((_strnicmp(access, "r", strlen(access)) == 0) ||
378  (_strnicmp(access, "rb", strlen(access)) == 0) ||
379  (_strnicmp(access, "rt", strlen(access)) == 0))
380  // Mac + Linux + iOS + Android
381 #elif defined(HF_PAK_USE_MMAP)
382  if ((strncasecmp(access, "r", strlen(access)) == 0) ||
383  (strncasecmp(access, "rb", strlen(access)) == 0) ||
384  (strncasecmp(access, "rt", strlen(access)) == 0))
385 #else
386 #error "Implement!"
387 #endif
388  {
389  int8_hf upperName[256];
390  fixFileName(fileName, upperName);
391 
392  PakRecordMap::iterator itr = mPakRecordMap.find(upperName);
393  if (itr != mPakRecordMap.end())
394  {
395  PFILE *fp = new PFILE;
396  fp->mRecord = itr->second;
397  fp->mPos = 0;
398  fp->mFP = NULL;
399  return fp;
400  }
401  }
402 
403  FILE *file = NULL;
404  // Windows
405 #if defined(HF_PLATFORM_WINDOWS)
406 #ifdef __MINGW32__
407  file = fopen(fileName, access);
408 #else
409  errno_t err = fopen_s(&file, fileName, access);
410 #endif
411  // Mac + Linux + iOS + Android
412 #elif defined(HF_PAK_USE_MMAP)
413  file = fopen(fileName, access);
414 #else
415 #error "Implement!"
416 #endif
417 
418  if (file == NULL)
419  return NULL;
420 
421  PFILE *fp = new PFILE;
422  fp->mRecord = NULL;
423  fp->mPos = 0;
424  fp->mFP = file;
425  return fp;
426 }
427 
428 PFILE *PakInterface::FOpen(const wchar_t *fileName, const wchar_t *access)
429 {
430  // Windows
431 #if defined(HF_PLATFORM_WINDOWS)
432  if ((_wcsnicmp(access, L"r", wcslen(access)) == 0) ||
433  (_wcsnicmp(access, L"rb", wcslen(access)) == 0) ||
434  (_wcsnicmp(access, L"rt", wcslen(access)) == 0))
435  // Mac + Linux + iOS + Android
436 #elif defined(HF_PAK_USE_MMAP)
437  std::wstring tmp = fileName;
438  std::wstring tmp2 = access;
439  std::string tmpFileName = StringUtil::WStringToString(tmp);
440  std::string tmpAccess = StringUtil::WStringToString(tmp2);
441  if ((strncasecmp(tmpAccess.c_str(), "r", strlen(tmpAccess.c_str())) == 0) ||
442  (strncasecmp(tmpAccess.c_str(), "rb", strlen(tmpAccess.c_str())) == 0) ||
443  (strncasecmp(tmpAccess.c_str(), "rt", strlen(tmpAccess.c_str())) == 0))
444 #else
445 #error "Implement!"
446 #endif
447  {
448  std::string fileNameTmp = StringUtil::WStringToString(fileName);
449  int8_hf upperName[256];
450  fixFileName(fileNameTmp.c_str(), upperName);
451 
452  PakRecordMap::iterator itr = mPakRecordMap.find(upperName);
453  if (itr != mPakRecordMap.end())
454  {
455  PFILE *fp = new PFILE;
456  fp->mRecord = itr->second;
457  fp->mPos = 0;
458  fp->mFP = NULL;
459  return fp;
460  }
461  }
462 
463  FILE *file = NULL;
464  // Windows
465 #if defined(HF_PLATFORM_WINDOWS)
466 #ifdef __MINGW32__
467  std::string tmpFileName = StringUtil::WStringToString(fileName);
468  std::string tmpAccess = StringUtil::WStringToString(access);
469  file = fopen(tmpFileName.c_str(), tmpAccess.c_str());
470 #else
471  _wfopen_s(&file, fileName, access);
472 #endif
473  // Mac + Linux + iOS + Android
474 #elif defined(HF_PAK_USE_MMAP)
475  file = fopen(tmpFileName.c_str(), tmpAccess.c_str());
476 #else
477 #error "Implement!"
478 #endif
479 
480  if (file == NULL)
481  return NULL;
482 
483  PFILE *fp = new PFILE;
484  fp->mRecord = NULL;
485  fp->mPos = 0;
486  fp->mFP = file;
487  return fp;
488 }
489 
491 {
492  if (file->mRecord == NULL)
493  fclose(file->mFP);
494 
495  HF_SAFE_DELETE(file);
496  return 0;
497 }
498 
499 int32_hf PakInterface::FSeek(PFILE *file, long offset, int32_hf origin)
500 {
501  if (file->mRecord != NULL)
502  {
503  if (origin == SEEK_SET)
504  file->mPos = offset;
505  else if (origin == SEEK_END)
506  file->mPos = file->mRecord->mSize - offset;
507  else if (origin == SEEK_CUR)
508  file->mPos += offset;
509 
510  file->mPos = hf_max(hf_min(file->mPos, file->mRecord->mSize), 0);
511  return 0;
512  }
513  else
514  return fseek(file->mFP, offset, origin);
515 }
516 
518 {
519  if (file->mRecord != NULL)
520  return file->mPos;
521  else
522  return ftell(file->mFP);
523 }
524 
525 size_t PakInterface::FRead(void *ptr, int32_hf elemSize, int32_hf count, PFILE *file)
526 {
527  if (file->mRecord != NULL)
528  {
529  int32_hf sizeBytes = hf_min(elemSize * count, file->mRecord->mSize - file->mPos);
530  uint8_hf *src = (uint8_hf *) file->mRecord->mCollection->mDataPtr +
531  file->mRecord->mStartPos + file->mPos;
532  uint8_hf *dest = (uint8_hf *) ptr;
533 
534  for (int32_hf i = 0; i < sizeBytes; i++)
535  {
536  *(dest++) = (*src++) ^ mPasswordHash; // 'Decrypt'
537  }
538 
539  file->mPos += sizeBytes;
540  return sizeBytes / elemSize;
541  }
542  return fread(ptr, elemSize, count, file->mFP);
543 }
544 
546 {
547  if (file->mRecord != NULL)
548  {
549  for (;;)
550  {
551  if (file->mPos >= file->mRecord->mSize)
552  return EOF;
553 
554  int8_hf ch = *((int8_hf *) file->mRecord->mCollection->mDataPtr +
555  file->mRecord->mStartPos + file->mPos++) ^ mPasswordHash;
556 
557  if (ch != '\r')
558  return (uint8_hf) ch;
559  }
560  }
561 
562  return fgetc(file->mFP);
563 }
564 
566 {
567  if (file->mRecord != NULL)
568  {
569  // This won't work if we're not pushing the same chars back in the stream
570  file->mPos = hf_max(file->mPos - 1, 0);
571  return ch;
572  }
573 
574  return ungetc(ch, file->mFP);
575 }
576 
578 {
579  if (file->mRecord != NULL)
580  {
581  int32_hf idx = 0;
582  while (idx < size)
583  {
584  if (file->mPos >= file->mRecord->mSize)
585  {
586  if (idx == 0)
587  return NULL;
588  break;
589  }
590 
591  int8_hf ch = *((int8_hf *) file->mRecord->mCollection->mDataPtr +
592  file->mRecord->mStartPos + file->mPos++) ^ mPasswordHash;
593 
594  if (ch != '\r')
595  ptr[idx++] = ch;
596  if (ch == '\n')
597  break;
598  }
599  ptr[idx] = 0;
600  return ptr;
601  }
602 
603  return fgets(ptr, size, file->mFP);
604 }
605 
607 {
608  if (file->mRecord != NULL)
609  return file->mPos >= file->mRecord->mSize;
610  else
611  return feof(file->mFP);
612 }
613 
614 #if defined(HF_PLATFORM_ANDROID)
615 int32_hf PakInterface::JNI_openFD(const std::string &fileName, int32_hf *outStart,
616  int32_hf *outLength)
617 {
618  int32_hf result = -1;
619  int32_hf start, length = -1;
620  *outStart = start;
621  *outLength = length;
622 
623  jmethodID mid;
624  jobject context;
625  jobject assetManager;
626  jobject assetFileFD;
627  jobject fileDescriptor;
628  jlong jstartoffset;
629  jlong jlength;
630  jstring fileNameJString;
631 
632  // create our JString for the JNI call:
633  fileNameJString = mEnv->NewStringUTF(fileName.c_str());
634 
635  // context = SDLActivity.getContext();
636  mid = mEnv->GetStaticMethodID(mActivityClass,
637  "getContext", "()Landroid/content/Context;");
638  assert(mid);
639  context = mEnv->CallStaticObjectMethod(mActivityClass, mid);
640  assert(context);
641 
642  // assetManager = context.getAssets();
643  mid = mEnv->GetMethodID(mEnv->GetObjectClass(context),
644  "getAssets", "()Landroid/content/res/AssetManager;");
645  assert(mid);
646  assetManager = mEnv->CallObjectMethod(context, mid);
647  assert(assetManager);
648 
649  // assetFileFD = assetManager.openFD(<filename>);
650  mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager),
651  "openFd", "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;");
652  assert(mid);
653  assetFileFD = mEnv->CallObjectMethod(assetManager, mid, fileNameJString);
654  assert(assetFileFD);
655 
656  // fileDescriptor = assetFileFD.getFileDescriptor();
657  mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetFileFD),
658  "getFileDescriptor", "()Ljava/io/FileDescriptor;");
659  assert(mid);
660  fileDescriptor = mEnv->CallObjectMethod(assetFileFD, mid);
661  assert(fileDescriptor);
662 
663  // jstartoffset = assetFileFD.getStartOffset();
664  mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetFileFD),
665  "getStartOffset", "()J");
666  assert(mid);
667  jstartoffset = mEnv->CallLongMethod(assetFileFD, mid);
668 
669  // jlength = assetFileFD.getLength();
670  mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetFileFD),
671  "getLength", "()J");
672  assert(mid);
673  jlength = mEnv->CallLongMethod(assetFileFD, mid);
674 
675  jclass fdClass = mEnv->FindClass("java/io/FileDescriptor");
676  if (fdClass != NULL)
677  {
678  jfieldID fdClassDescriptorFieldID = mEnv->GetFieldID(fdClass, "descriptor", "I");
679 
680  if (fdClassDescriptorFieldID != NULL && fileDescriptor != NULL)
681  {
682  // convert fd:
683  jint fd = mEnv->GetIntField(fileDescriptor, fdClassDescriptorFieldID);
684  int32_hf fdresult = dup(fd);
685 
686  // set return value to opened FD:
687  result = fdresult;
688  }
689  }
690  // free jstring:
691  mEnv->DeleteLocalRef(fileNameJString);
692 
693  // set output values:
694  start = (int32_hf)jstartoffset;
695  length = (int32_hf)jlength;
696  *outStart = start;
697  *outLength = length;
698 
699  // return fd:
700  return result;
701 }
702 #endif // #if defined(HF_PLATFORM_ANDROID)
703 
705 {
706  // Windows
707 #if defined(HF_PLATFORM_WINDOWS)
708  if (gPakFileMapping == NULL)
709  {
710  int8_hf name[256];
711 
712 #ifdef __MINGW32__
713  sprintf(name, "gPakInterfaceP_%lu", GetCurrentProcessId());
714 #else
715  sprintf_s(name, 256, "gPakInterfaceP_%lu", GetCurrentProcessId());
716 #endif
717  gPakFileMapping = ::CreateFileMappingA((HANDLE)INVALID_HANDLE_VALUE, NULL,
718  PAGE_READWRITE, 0, sizeof(HFCore::PakInterface *), name);
719  gPakInterfaceP = (PakInterfaceBase **) MapViewOfFile(gPakFileMapping, FILE_MAP_ALL_ACCESS,
720  0, 0, sizeof(HFCore::PakInterface *));
721  }
722  return *gPakInterfaceP;
723  // Mac + Linux + iOS + Android
724 #elif defined(HF_PAK_USE_MMAP)
725  return gPakInterface;
726 #else
727 #error "Implement!"
728 #endif
729 }
730 
731 HFCore::PFILE *p_fopen(const int8_hf *fileName, const int8_hf *access)
732 {
733  if (getPakPtr() != NULL)
734  return getPakPtr()->FOpen(fileName, access);
735 
736  FILE *file = NULL;
737  // Windows
738 #if defined(HF_PLATFORM_WINDOWS)
739 #ifdef __MINGW32__
740  file = fopen(fileName, access);
741 #else
742  errno_t err = fopen_s(&file, fileName, access);
743 #endif
744  // Mac + Linux + iOS + Android
745 #elif defined(HF_PAK_USE_MMAP)
746  file = fopen(fileName, access);
747 #else
748 #error "Implement!"
749 #endif
750 
751  if (file == NULL)
752  return NULL;
753 
754  HFCore::PFILE *pFile = new HFCore::PFILE;
755  pFile->mRecord = NULL;
756  pFile->mPos = 0;
757  pFile->mFP = file;
758  return pFile;
759 }
760 
761 HFCore::PFILE *p_fopen(const wchar_t *fileName, const wchar_t *access)
762 {
763  if (getPakPtr() != NULL)
764  return getPakPtr()->FOpen(fileName, access);
765 
766  FILE *file = NULL;
767  // Windows
768 #if defined(HF_PLATFORM_WINDOWS)
769 #ifdef __MINGW32__
770  std::string tmpFileName = HFCore::StringUtil::WStringToString(fileName);
771  std::string tmpAccess = HFCore::StringUtil::WStringToString(access);
772  file = fopen(tmpFileName.c_str(), tmpAccess.c_str());
773 #else
774  _wfopen_s(&file, fileName, access);
775 #endif
776  // Mac + Linux + iOS + Android
777 #elif defined(HF_PAK_USE_MMAP)
778  std::wstring tmp = fileName;
779  std::wstring tmp2 = access;
780  std::string tmpFileName = HFCore::StringUtil::WStringToString(tmp);
781  std::string tmpAccess = HFCore::StringUtil::WStringToString(tmp2);
782  file = fopen(tmpFileName.c_str(), tmpAccess.c_str());
783 #else
784 #error "Implement!"
785 #endif
786 
787  if (file == NULL)
788  return NULL;
789 
790  HFCore::PFILE *pFile = new HFCore::PFILE;
791  pFile->mRecord = NULL;
792  pFile->mPos = 0;
793  pFile->mFP = file;
794  return pFile;
795 }
796 
798 {
799  if (getPakPtr() != NULL)
800  return getPakPtr()->FClose(file);
801 
802  int32_hf result = fclose(file->mFP);
803  HF_SAFE_DELETE(file);
804  return result;
805 }
806 
807 int32_hf p_fseek(HFCore::PFILE *file, long offset, int32_hf origin)
808 {
809  if (getPakPtr() != NULL)
810  return getPakPtr()->FSeek(file, offset, origin);
811 
812  return fseek(file->mFP, offset, origin);
813 }
814 
816 {
817  if (getPakPtr() != NULL)
818  return getPakPtr()->FTell(file);
819 
820  return ftell(file->mFP);
821 }
822 
823 size_t p_fread(void *ptr, int32_hf size, int32_hf count, HFCore::PFILE *file)
824 {
825  if (getPakPtr() != NULL)
826  return getPakPtr()->FRead(ptr, size, count, file);
827 
828  return fread(ptr, size, count, file->mFP);
829 }
830 
831 size_t p_fwrite(const void *ptr, int32_hf size, int32_hf count, HFCore::PFILE *file)
832 {
833  if (file->mFP == NULL)
834  return 0;
835 
836  return fwrite(ptr, size, count, file->mFP);
837 }
838 
840 {
841  if (getPakPtr() != NULL)
842  return getPakPtr()->FGetC(file);
843 
844  return fgetc(file->mFP);
845 }
846 
848 {
849  if (getPakPtr() != NULL)
850  return getPakPtr()->UnGetC(ch, file);
851 
852  return ungetc(ch, file->mFP);
853 }
854 
856 {
857  if (getPakPtr() != NULL)
858  return getPakPtr()->FGetS(ptr, size, file);
859 
860  return fgets(ptr, size, file->mFP);
861 }
862 
863 wchar_t *p_fgets(wchar_t *ptr, int32_hf size, HFCore::PFILE *file)
864 {
865  if (getPakPtr() != NULL)
866  return getPakPtr()->FGetS(ptr, size, file);
867 
868  return fgetws(ptr, size, file->mFP);
869 }
870 
872 {
873  if (getPakPtr() != NULL)
874  return getPakPtr()->FEof(file);
875 
876  return feof(file->mFP);
877 }
unsigned int uint32_hf
A type definition for unsigned int.
Definition: HFDataTypes.h:354
Interface representing the actual memory mapped pak file.
Definition: PakInterface.h:100
virtual int8_hf * makeFilePath(int8_hf *fileName)
Builds full file path to file on platforms where relative paths doesn&#39;t work such as iOS and Mac...
Definition: FileDirUtils.h:100
virtual int8_hf * FGetS(int8_hf *ptr, int32_hf size, PFILE *file)=0
Get string from stream.
virtual int32_hf FSeek(PFILE *file, long offset, int32_hf origin)=0
Sets the position indicator associated with the stream to a new position.
virtual int32_hf FTell(PFILE *file)
Returns the current value of the position indicator of the PFILE stream.
Interface which implements base interface PakInterfaceBase.
Definition: PakInterface.h:381
Interface for unicode string class UString.
Definition: UString.h:35
#define HF_SAFE_DELETE(p)
Check if not NULL, delete and set to NULL.
Definition: HFDataTypes.h:49
HFCore::PFILE * p_fopen(const int8_hf *fileName, const int8_hf *access)
Open a file (within pak file or outside of it).
int int32_hf
A type definition for int.
Definition: HFDataTypes.h:349
HFCore::PakInterface * gPakInterface
Global that should be used to create the HFCore::PakInterface instance.
uint32_hf getASCIISum(const std::string &s)
Get ASCII sum for a given string.
bool addPakFile(const std::string &fileName, const std::string &decryptPassword)
Add a new pak file to be memory mapped and decrypted using decryptPassword.
static std::wstring StringToWString(const std::string &string)
Convert std::string to std::wstring.
Definition: StringUtil.cpp:482
int32_hf p_fclose(HFCore::PFILE *file)
Closes and deletes a HFCore::PFILE.
PakInterface(FileDirUtils *fileDirUtils)
Constructor.
virtual PFILE * FOpen(const int8_hf *fileName, const int8_hf *access)=0
Open a file (within pak file or outside of it).
int32_hf mPos
File position.
Definition: PakInterface.h:149
size_t p_fread(void *ptr, int32_hf size, int32_hf count, HFCore::PFILE *file)
Reads an array of count elements, each one with a size of size bytes, from the stream and stores them...
virtual int32_hf FSeek(PFILE *file, long offset, int32_hf origin)
Sets the position indicator associated with the stream to a new position.
HFCore::PakInterfaceBase * getPakPtr()
Get a pointer to global gPakInterface.
virtual int32_hf FClose(PFILE *file)=0
Closes and deletes a PFILE.
virtual int32_hf FGetC(PFILE *file)
Get character from PFILE stream.
size_t p_fwrite(const void *ptr, int32_hf size, int32_hf count, HFCore::PFILE *file)
Write block of data to HFCore::PFILE stream.
void * mDataPtr
void pointer to data.
Definition: PakInterface.h:118
int32_hf mStartPos
Holds start position.
Definition: PakInterface.h:89
std::string mDecryptPassword
Decryption password to use for each file within pak file.
Definition: PakInterface.h:129
#define NULL
Convenient define for 0.
Definition: HFDataTypes.h:42
virtual size_t FRead(void *ptr, int32_hf elemSize, int32_hf count, PFILE *file)=0
Reads an array of count elements, each one with a size of elemSize bytes, from the stream and stores ...
PakRecord * mRecord
Pointer to PakRecord.
Definition: PakInterface.h:148
virtual ~PakInterface()
Destructor.
Interface representing an individual record within pak file.
Definition: PakInterface.h:73
virtual int8_hf * FGetS(int8_hf *ptr, int32_hf size, PFILE *file)
Get string from stream.
int32_hf length() const
Get the length of the string.
Definition: UString.cpp:178
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 int32_hf UnGetC(int32_hf ch, PFILE *file)=0
Unget character from PFILE stream.
int32_hf p_fseek(HFCore::PFILE *file, long offset, int32_hf origin)
Sets the position indicator associated with the stream to a new position.
virtual int32_hf FEof(PFILE *file)
Check end-of-file indicator.
#define hf_min(a, b)
Returns the smallest of a and b.
Definition: HFDataTypes.h:123
int32_hf p_fgetc(HFCore::PFILE *file)
Get character from HFCore::PFILE stream.
FILE * mFP
Pointer to FILE.
Definition: PakInterface.h:150
PakCollection * mCollection
Pointer to PakCollection interface.
Definition: PakInterface.h:79
int32_hf mFileHandle
Holds a handle to the memory mapped file.
Definition: PakInterface.h:111
PakRecordMap mPakRecordMap
std::map holding PakRecord pointers indexed by uppername file path.
Definition: PakInterface.h:393
virtual int32_hf FTell(PFILE *file)=0
Returns the current value of the position indicator of the PFILE stream.
virtual int32_hf FClose(PFILE *file)
Closes and deletes a PFILE.
Interface useful for generic directory and file operations.
Definition: FileDirUtils.h:57
Definition: Actor.h:34
virtual int32_hf FEof(PFILE *file)=0
Check end-of-file indicator.
Singleton interface for platform specific things.
virtual PFILE * FOpen(const int8_hf *fileName, const int8_hf *access)
Open a file (within pak file or outside of it).
Struct holding PakRecord, pointer to actual FILE and position.
Definition: PakInterface.h:146
Base interface for implementors to use.
Definition: PakInterface.h:156
static std::string StringToUpper(const std::string &string)
Convert string to uppercase.
Definition: StringUtil.cpp:442
int8_hf * p_fgets(int8_hf *ptr, int32_hf size, HFCore::PFILE *file)
Get string from stream.
#define HFCORE_ENV
Get HFCore::Environment instance shortcut macro.
Definition: Environment.h:68
int32_hf mFileSize
Pak file size.
Definition: PakInterface.h:123
virtual int32_hf UnGetC(int32_hf ch, PFILE *file)
Unget character from PFILE stream.
static std::string WStringToString(const std::wstring &string)
Convert std::wstring to std::string.
Definition: StringUtil.cpp:490
int32_hf p_ftell(HFCore::PFILE *file)
Returns the current value of the position indicator of the HFCore::PFILE stream.
unsigned char uint8_hf
A type definition for unsigned char.
Definition: HFDataTypes.h:334
int32_hf mSize
Holds file size.
Definition: PakInterface.h:94
int32_hf p_feof(HFCore::PFILE *file)
Check end-of-file indicator.
#define hf_max(a, b)
Returns the largest of a and b.
Definition: HFDataTypes.h:116
virtual size_t FRead(void *ptr, int32_hf elemSize, int32_hf count, PFILE *file)
Reads an array of count elements, each one with a size of elemSize bytes, from the stream and stores ...
PakCollectionList mPakCollectionList
std::list holding PakCollection pointers.
Definition: PakInterface.h:387
Interface for accessing pak files created with tool hfpak.
std::string mFileName
Holds file name.
Definition: PakInterface.h:84
virtual int32_hf FGetC(PFILE *file)=0
Get character from PFILE stream.
Interface for string related helper methods.
int32_hf p_ungetc(int32_hf ch, HFCore::PFILE *file)
Unget character from HFCore::PFILE stream.