alfstream.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #include "config.h"
  2. #include "alfstream.h"
  3. #include "strutils.h"
  4. #ifdef _WIN32
  5. namespace al {
  6. auto filebuf::underflow() -> int_type
  7. {
  8. if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr())
  9. {
  10. // Read in the next chunk of data, and set the pointers on success
  11. DWORD got{};
  12. if(ReadFile(mFile, mBuffer.data(), static_cast<DWORD>(mBuffer.size()), &got, nullptr))
  13. setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got);
  14. }
  15. if(gptr() == egptr())
  16. return traits_type::eof();
  17. return traits_type::to_int_type(*gptr());
  18. }
  19. auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type
  20. {
  21. if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in))
  22. return traits_type::eof();
  23. LARGE_INTEGER fpos{};
  24. switch(whence)
  25. {
  26. case std::ios_base::beg:
  27. fpos.QuadPart = offset;
  28. if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN))
  29. return traits_type::eof();
  30. break;
  31. case std::ios_base::cur:
  32. // If the offset remains in the current buffer range, just
  33. // update the pointer.
  34. if((offset >= 0 && offset < off_type(egptr()-gptr())) ||
  35. (offset < 0 && -offset <= off_type(gptr()-eback())))
  36. {
  37. // Get the current file offset to report the correct read
  38. // offset.
  39. fpos.QuadPart = 0;
  40. if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT))
  41. return traits_type::eof();
  42. setg(eback(), gptr()+offset, egptr());
  43. return fpos.QuadPart - off_type(egptr()-gptr());
  44. }
  45. // Need to offset for the file offset being at egptr() while
  46. // the requested offset is relative to gptr().
  47. offset -= off_type(egptr()-gptr());
  48. fpos.QuadPart = offset;
  49. if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT))
  50. return traits_type::eof();
  51. break;
  52. case std::ios_base::end:
  53. fpos.QuadPart = offset;
  54. if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END))
  55. return traits_type::eof();
  56. break;
  57. default:
  58. return traits_type::eof();
  59. }
  60. setg(nullptr, nullptr, nullptr);
  61. return fpos.QuadPart;
  62. }
  63. auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type
  64. {
  65. // Simplified version of seekoff
  66. if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in))
  67. return traits_type::eof();
  68. LARGE_INTEGER fpos{};
  69. fpos.QuadPart = pos;
  70. if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN))
  71. return traits_type::eof();
  72. setg(nullptr, nullptr, nullptr);
  73. return fpos.QuadPart;
  74. }
  75. filebuf::~filebuf()
  76. {
  77. if(mFile != INVALID_HANDLE_VALUE)
  78. CloseHandle(mFile);
  79. mFile = INVALID_HANDLE_VALUE;
  80. }
  81. bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode)
  82. {
  83. if((mode&std::ios_base::out) || !(mode&std::ios_base::in))
  84. return false;
  85. HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
  86. FILE_ATTRIBUTE_NORMAL, nullptr)};
  87. if(f == INVALID_HANDLE_VALUE) return false;
  88. if(mFile != INVALID_HANDLE_VALUE)
  89. CloseHandle(mFile);
  90. mFile = f;
  91. setg(nullptr, nullptr, nullptr);
  92. return true;
  93. }
  94. bool filebuf::open(const char *filename, std::ios_base::openmode mode)
  95. {
  96. std::wstring wname{utf8_to_wstr(filename)};
  97. return open(wname.c_str(), mode);
  98. }
  99. ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode)
  100. : std::istream{nullptr}
  101. {
  102. init(&mStreamBuf);
  103. // Set the failbit if the file failed to open.
  104. if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in))
  105. clear(failbit);
  106. }
  107. ifstream::ifstream(const char *filename, std::ios_base::openmode mode)
  108. : std::istream{nullptr}
  109. {
  110. init(&mStreamBuf);
  111. // Set the failbit if the file failed to open.
  112. if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in))
  113. clear(failbit);
  114. }
  115. /* This is only here to ensure the compiler doesn't define an implicit
  116. * destructor, which it tries to automatically inline and subsequently complain
  117. * it can't inline without excessive code growth.
  118. */
  119. ifstream::~ifstream() { }
  120. } // namespace al
  121. #endif