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. {
  52. fill_fopen64_filefunc(&MinizipFilefunc);
  53. MinizipFilefunc.zopen64_file = &MinizipOpenFunc;
  54. initialized = true;
  55. }
  56. return &MinizipFilefunc;
  57. }
  58. template class boost::iostreams::stream<FileBuf>;
  59. /*static*/
  60. bool FileStream::CreateFile(const boost::filesystem::path& filename)
  61. {
  62. FILE* f = do_open(filename.c_str(), CHAR_LITERAL("wb"));
  63. bool result = (f != nullptr);
  64. fclose(f);
  65. return result;
  66. }
  67. FileBuf::FileBuf(const boost::filesystem::path& filename, std::ios_base::openmode mode)
  68. {
  69. auto openmode = [mode]() -> std::basic_string<CharType>
  70. {
  71. using namespace std;
  72. switch (mode & (~ios_base::ate & ~ios_base::binary))
  73. {
  74. case (ios_base::in):
  75. return CHAR_LITERAL("r");
  76. case (ios_base::out):
  77. case (ios_base::out | ios_base::trunc):
  78. return CHAR_LITERAL("w");
  79. case (ios_base::app):
  80. case (ios_base::out | ios_base::app):
  81. return CHAR_LITERAL("a");
  82. case (ios_base::out | ios_base::in):
  83. return CHAR_LITERAL("r+");
  84. case (ios_base::out | ios_base::in | ios_base::trunc):
  85. return CHAR_LITERAL("w+");
  86. case (ios_base::out | ios_base::in | ios_base::app):
  87. case (ios_base::in | ios_base::app):
  88. return CHAR_LITERAL("a+");
  89. default:
  90. throw std::ios_base::failure("invalid open mode");
  91. }
  92. }();
  93. if (mode & std::ios_base::binary)
  94. openmode += CHAR_LITERAL('b');
  95. filePtr = do_open(filename.c_str(), openmode.c_str());
  96. if (filePtr == nullptr)
  97. throw std::ios_base::failure("could not open file");
  98. if (mode & std::ios_base::ate) {
  99. if (std::fseek(GETFILE, 0, SEEK_END)) {
  100. fclose(GETFILE);
  101. throw std::ios_base::failure("could not open file");
  102. }
  103. }
  104. }
  105. void FileBuf::close()
  106. {
  107. std::fclose(GETFILE);
  108. }
  109. std::streamsize FileBuf::read(char* s, std::streamsize n)
  110. {
  111. return static_cast<std::streamsize>(std::fread(s, 1, n, GETFILE));
  112. }
  113. std::streamsize FileBuf::write(const char* s, std::streamsize n)
  114. {
  115. return static_cast<std::streamsize>(std::fwrite(s, 1, n, GETFILE));
  116. }
  117. std::streamoff FileBuf::seek(std::streamoff off, std::ios_base::seekdir way)
  118. {
  119. const auto src = [way]() -> int
  120. {
  121. switch(way)
  122. {
  123. case std::ios_base::beg:
  124. return SEEK_SET;
  125. case std::ios_base::cur:
  126. return SEEK_CUR;
  127. case std::ios_base::end:
  128. return SEEK_END;
  129. default:
  130. throw std::ios_base::failure("bad seek direction");
  131. }
  132. }();
  133. if(std::fseek(GETFILE, off, src))
  134. throw std::ios_base::failure("bad seek offset");
  135. return static_cast<std::streamsize>(std::ftell(GETFILE));
  136. }