FStream.h (3643B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Similar to std::ifstream/ofstream, but takes char16ptr_t on Windows. 8 // Until C++17, std functions can only take char* filenames. So Unicode 9 // filenames were lost on Windows. To address this limitations, this wrapper 10 // uses proprietary wchar_t* overloads on MSVC, and __gnu_cxx::stdio_filebuf 11 // extension on MinGW. Once we can use C++17 filesystem API everywhere, 12 // we will be able to avoid this wrapper. 13 14 #ifndef mozilla_FStream_h 15 #define mozilla_FStream_h 16 17 #include "mozilla/Char16.h" 18 #include <istream> 19 #include <ostream> 20 #include <fstream> 21 #if defined(__MINGW32__) && defined(__GLIBCXX__) 22 # include "mozilla/UniquePtr.h" 23 # include <fcntl.h> 24 # include <ext/stdio_filebuf.h> 25 #endif 26 27 namespace mozilla { 28 29 #if defined(__MINGW32__) && defined(__GLIBCXX__) 30 // MinGW does not support wchar_t* overloads that are MSVC extension until 31 // C++17, so we have to implement widechar wrappers using a GNU extension. 32 class IFStream : public std::istream { 33 public: 34 explicit IFStream(char16ptr_t filename, openmode mode = in); 35 36 std::filebuf* rdbuf() const { return mFileBuf.get(); } 37 38 bool is_open() const { return mFileBuf && mFileBuf->is_open(); } 39 void open(char16ptr_t filename, openmode mode = in); 40 void close() { mFileBuf && mFileBuf->close(); } 41 42 private: 43 UniquePtr<std::filebuf> mFileBuf; 44 }; 45 46 inline IFStream::IFStream(char16ptr_t filename, openmode mode) 47 : std::istream(nullptr) { 48 open(filename, mode); 49 } 50 51 inline void IFStream::open(char16ptr_t filename, openmode mode) { 52 int fmode = _O_RDONLY; 53 if (mode & binary) { 54 fmode |= _O_BINARY; 55 } else { 56 fmode |= _O_TEXT; 57 } 58 int fd = _wopen(filename, fmode); 59 mFileBuf = MakeUnique<__gnu_cxx::stdio_filebuf<char>>(fd, mode); 60 std::istream::rdbuf(mFileBuf.get()); 61 } 62 63 class OFStream : public std::ostream { 64 public: 65 explicit OFStream(char16ptr_t filename, openmode mode = out); 66 67 std::filebuf* rdbuf() const { return mFileBuf.get(); } 68 69 bool is_open() const { return mFileBuf && mFileBuf->is_open(); } 70 void open(char16ptr_t filename, openmode mode = out); 71 void close() { mFileBuf && mFileBuf->close(); } 72 73 private: 74 UniquePtr<std::filebuf> mFileBuf; 75 }; 76 77 inline OFStream::OFStream(char16ptr_t filename, openmode mode) 78 : std::ostream(nullptr) { 79 open(filename, mode); 80 } 81 82 inline void OFStream::open(char16ptr_t filename, openmode mode) { 83 int fmode = _O_WRONLY; 84 if (mode & binary) { 85 fmode |= _O_BINARY; 86 } else { 87 fmode |= _O_TEXT; 88 } 89 if (mode & trunc) { 90 fmode |= _O_CREAT | _O_TRUNC; 91 } 92 int fd = _wopen(filename, fmode); 93 mFileBuf = MakeUnique<__gnu_cxx::stdio_filebuf<char>>(fd, mode); 94 std::ostream::rdbuf(mFileBuf.get()); 95 } 96 97 #elif defined(XP_WIN) 98 class IFStream : public std::ifstream { 99 public: 100 explicit IFStream(char16ptr_t filename, openmode mode = in) 101 : std::ifstream(filename, mode) {} 102 103 void open(char16ptr_t filename, openmode mode = in) { 104 std::ifstream::open(filename, mode); 105 } 106 }; 107 108 class OFStream : public std::ofstream { 109 public: 110 explicit OFStream(char16ptr_t filename, openmode mode = out) 111 : std::ofstream(filename, mode) {} 112 113 void open(char16ptr_t filename, openmode mode = out) { 114 std::ofstream::open(filename, mode); 115 } 116 }; 117 #else 118 using IFStream = std::ifstream; 119 using OFStream = std::ofstream; 120 #endif 121 122 } // namespace mozilla 123 124 #endif /* mozilla_FStream_h */