FileStream.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "StdInc.h"
  2. #include "FileStream.h"
  3. #ifdef USE_SYSTEM_MINIZIP
  4. #include <minizip/unzip.h>
  5. #else
  6. #include "../minizip/unzip.h"
  7. #endif
  8. #include <cstdio>
  9. #ifdef VCMI_WINDOWS
  10. #ifndef _CRT_SECURE_NO_WARNINGS
  11. #define _CRT_SECURE_NO_WARNINGS
  12. #endif
  13. #include <cwchar>
  14. #define CHAR_LITERAL(s) L##s
  15. using CharType = wchar_t;
  16. #else
  17. #define CHAR_LITERAL(s) s
  18. using CharType = char;
  19. #endif
  20. inline FILE* do_open(const CharType* name, const CharType* mode)
  21. {
  22. #ifdef VCMI_WINDOWS
  23. return _wfopen(name, mode);
  24. #else
  25. return std::fopen(name, mode);
  26. #endif
  27. }
  28. #define GETFILE static_cast<std::FILE*>(filePtr)
  29. voidpf ZCALLBACK MinizipOpenFunc(voidpf opaque, const void* filename, int mode)
  30. {
  31. const CharType* mode_fopen = [mode]() -> const CharType*
  32. {
  33. if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
  34. return CHAR_LITERAL("rb");
  35. else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
  36. return CHAR_LITERAL("r+b");
  37. else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
  38. return CHAR_LITERAL("wb");
  39. return nullptr;
  40. }();
  41. if (filename != nullptr && mode_fopen != nullptr)
  42. return do_open(static_cast<const CharType*>(filename), mode_fopen);
  43. else
  44. return nullptr;
  45. }
  46. zlib_filefunc64_def* FileStream::GetMinizipFilefunc()
  47. {
  48. static zlib_filefunc64_def MinizipFilefunc;
  49. static bool initialized = false;
  50. if (!initialized) {
  51. fill_fopen64_filefunc((&MinizipFilefunc));
  52. MinizipFilefunc.zopen64_file = &MinizipOpenFunc;
  53. initialized = true;
  54. }
  55. return &MinizipFilefunc;
  56. }
  57. template class boost::iostreams::stream<FileBuf>;
  58. /*static*/
  59. bool FileStream::CreateFile(const boost::filesystem::path& filename)
  60. {
  61. FILE* f = do_open(filename.c_str(), CHAR_LITERAL("wb"));
  62. bool result = (f != nullptr);
  63. fclose(f);
  64. return result;
  65. }
  66. FileBuf::FileBuf(const boost::filesystem::path& filename, std::ios_base::openmode mode)
  67. {
  68. auto openmode = [mode]() -> std::basic_string<CharType>
  69. {
  70. using namespace std;
  71. switch (mode & (~ios_base::ate & ~ios_base::binary))
  72. {
  73. case (ios_base::in):
  74. return CHAR_LITERAL("r");
  75. case (ios_base::out):
  76. case (ios_base::out | ios_base::trunc):
  77. return CHAR_LITERAL("w");
  78. case (ios_base::app):
  79. case (ios_base::out | ios_base::app):
  80. return CHAR_LITERAL("a");
  81. case (ios_base::out | ios_base::in):
  82. return CHAR_LITERAL("r+");
  83. case (ios_base::out | ios_base::in | ios_base::trunc):
  84. return CHAR_LITERAL("w+");
  85. case (ios_base::out | ios_base::in | ios_base::app):
  86. case (ios_base::in | ios_base::app):
  87. return CHAR_LITERAL("a+");
  88. default:
  89. throw std::ios_base::failure("invalid open mode");
  90. }
  91. }();
  92. if (mode & std::ios_base::binary)
  93. openmode += CHAR_LITERAL('b');
  94. filePtr = do_open(filename.c_str(), openmode.c_str());
  95. if (filePtr == nullptr)
  96. throw std::ios_base::failure("could not open file");
  97. if (mode & std::ios_base::ate) {
  98. if (std::fseek(GETFILE, 0, SEEK_END)) {
  99. fclose(GETFILE);
  100. throw std::ios_base::failure("could not open file");
  101. }
  102. }
  103. }
  104. void FileBuf::close()
  105. {
  106. std::fclose(GETFILE);
  107. }
  108. std::streamsize FileBuf::read(char* s, std::streamsize n)
  109. {
  110. return static_cast<std::streamsize>(std::fread(s, 1, n, GETFILE));
  111. }
  112. std::streamsize FileBuf::write(const char* s, std::streamsize n)
  113. {
  114. return static_cast<std::streamsize>(std::fwrite(s, 1, n, GETFILE));
  115. }
  116. std::streamoff FileBuf::seek(std::streamoff off, std::ios_base::seekdir way)
  117. {
  118. const auto src = [way]() -> int
  119. {
  120. switch(way)
  121. {
  122. case std::ios_base::beg:
  123. return SEEK_SET;
  124. case std::ios_base::cur:
  125. return SEEK_CUR;
  126. case std::ios_base::end:
  127. return SEEK_END;
  128. default:
  129. throw std::ios_base::failure("bad seek direction");
  130. }
  131. }();
  132. if(std::fseek(GETFILE, off, src))
  133. throw std::ios_base::failure("bad seek offset");
  134. return static_cast<std::streamsize>(std::ftell(GETFILE));
  135. }