/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0(the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright(C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ // First checked in on 98/11/20 by John R. McMullen in the wrong directory. // Checked in again 98/12/04. // Polished version 98/12/08. //======================================================================================== // // Classes defined: // // single-byte char: // // nsInputFileStream, nsOutputFileStream, nsIOFileStream // // wide char: // // nsWideInputFileStream, nsWideOutputFileStream, nsWideIOFileStream // // This suite provide the following services: // // 1. Encapsulates all platform-specific file details, so that file i/o // can be done correctly without any platform #ifdefs // // 2. Uses NSPR file services (NOT ansi file I/O), in order to get best // native performance. This performance difference is especially large on // macintosh. // // 3. Allows all the power of the ansi stream syntax: these streams // ARE derived classes of ostream, istream, and iostream. ALL METHODS OF // istream, ostream, AND iostream ARE AVAILABLE! // // Basic example: // // nsFilePath myPath("/Development/iotest.txt"); // // nsOutputFileStream testStream(myPath); // testStream << "Hello World" << endl; // // 4. Requires streams to be constructed using typesafe nsFilePath specifier // (not the notorious and bug prone const char*), namely nsFilePath. See // nsFileSpec.h for more details. // // 5. Fixes a two bugs that have been there for a long time, and // are inevitable if you use NSPR alone: // // The problem on platforms (Macintosh) in which a path does not fully // specify a file. // // Not yet provided: // // Endian-awareness for reading and writing crossplatform binary files. At this // time there seems to be no demand for this. // //======================================================================================== #ifndef _FILESTREAM_H_ #define _FILESTREAM_H_ #ifdef XP_MAC #include "pprio.h" // To get PR_ImportFile #else #include "prio.h" #endif #include "nsFileSpec.h" //======================================================================================== // Compiler-specific macros, as needed //======================================================================================== #if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(XP_PC)) #define NS_USING_NAMESPACE #endif #ifdef NS_USING_NAMESPACE #define NS_NAMESPACE_PROTOTYPE #define NS_NAMESPACE namespace #define NS_NAMESPACE_END #define BASIC_STREAMBUF basic_streambuf #define IOS_BASE ios_base #include using std::ios_base; using std::basic_streambuf; using std::codecvt_base; using std::codecvt; using std::streamsize; using std::locale; using std::basic_istream; using std::basic_ostream; using std::basic_iostream; using std::char_traits; #else #define NS_NAMESPACE_PROTOTYPE static #define NS_NAMESPACE struct #define NS_NAMESPACE_END ; #define BASIC_STREAMBUF streambuf #define IOS_BASE ios #include #endif // NS_USING_NAMESPACE #ifdef __MWERKS__ #ifdef MSIPL_WCHART #define NS_USING_WIDE_CHAR #endif #ifdef MSIPL_EXPLICIT_FUNC_TEMPLATE_ARG #define NS_EXPLICIT_FUNC_TEMPLATE_ARG #endif #define NS_READ_LOCK(mut) READ_LOCK(mut) #define NS_WRITE_LOCK(mut) WRITE_LOCK(mut) #else // Fix me for thread-safety. #define NS_READ_LOCK(mut) #define NS_WRITE_LOCK(mut) #endif // __MWERKS__ //=========================== End Compiler-specific macros =============================== //======================================================================================== NS_NAMESPACE nsFileStreamHelpers // Prototypes for common (non-template) implementations in the .cpp file which do not // need the template args (charT, traits). //======================================================================================== { NS_NAMESPACE_PROTOTYPE PRFileDesc* open( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode); } NS_NAMESPACE_END // nsFileStreamHelpers //======================================================================================== // Template declarations //======================================================================================== //======================================================================================== template class nsFileBufferT //======================================================================================== : public BASIC_STREAMBUF { typedef codecvt_base::result result; public: typedef charT char_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef typename traits::int_type int_type; typedef traits traits_type; typedef typename traits::state_type state_type; typedef nsFileBufferT filebuf_type; typedef codecvt ofacet_type; typedef codecvt ifacet_type; nsFileBufferT(); nsFileBufferT(PRFileDesc* pfile_arg); virtual ~nsFileBufferT(); bool is_open() const; filebuf_type* open( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode); filebuf_type* close(); protected: virtual int_type overflow(int_type c=traits::eof()); virtual int_type pbackfail(int_type c=traits::eof()); virtual int_type underflow(); virtual pos_type seekoff( off_type off, IOS_BASE::seekdir way, IOS_BASE::openmode which=IOS_BASE::in|IOS_BASE::out); virtual pos_type seekpos(pos_type sp, IOS_BASE::openmode which=IOS_BASE::in|IOS_BASE::out); virtual BASIC_STREAMBUF* setbuf(char_type* s, streamsize n); virtual int sync(); virtual int_type uflow(); virtual void imbue(const locale& loc); virtual streamsize showmanyc(); virtual streamsize xsgetn(char_type* s, streamsize n); virtual streamsize xsputn(const char_type* s, streamsize n); private: PRFileDesc* mFileDesc; IOS_BASE::openmode mode_; }; // class nsFileBufferT //======================================================================================== template class nsInputFileStreamT //======================================================================================== : public basic_istream { typedef nsFileBufferT filebuf_type; public: typedef charT char_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef typename traits::int_type int_type; typedef traits traits_type; nsInputFileStreamT(); explicit nsInputFileStreamT( const nsFilePath& inFile, IOS_BASE::openmode mode=IOS_BASE::in, PRIntn accessMode = 0x00400); virtual ~nsInputFileStreamT(); filebuf_type* rdbuf() const; inline bool is_open(); inline void open( const nsFilePath& inFile, IOS_BASE::openmode mode=IOS_BASE::in, PRIntn accessMode = 0x00400); inline void close(); private: filebuf_type mBuffer; }; // class nsInputFileStreamT //======================================================================================== template class nsOutputFileStreamT //======================================================================================== : public basic_ostream { typedef nsFileBufferT filebuf_type; public: typedef charT char_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef typename traits::int_type int_type; typedef traits traits_type; nsOutputFileStreamT(); explicit nsOutputFileStreamT( const nsFilePath& inFile, IOS_BASE::openmode mode = IOS_BASE::out|IOS_BASE::trunc, PRIntn accessMode = 0x00200); virtual ~nsOutputFileStreamT(); filebuf_type* rdbuf() const; inline bool is_open(); inline void open( const nsFilePath& inFile, IOS_BASE::openmode mode = IOS_BASE::out|IOS_BASE::trunc, PRIntn accessMode = 0x00200); inline void close(); private: filebuf_type mBuffer; }; // class nsOutputFileStreamT //======================================================================================== // Implementation of nsFileBufferT //======================================================================================== //---------------------------------------------------------------------------------------- template inline nsFileBufferT::nsFileBufferT() : BASIC_STREAMBUF(), mFileDesc(NULL) //---------------------------------------------------------------------------------------- { } //---------------------------------------------------------------------------------------- template inline nsFileBufferT::nsFileBufferT(PRFileDesc* pfarg) : BASIC_STREAMBUF(), mFileDesc(pfarg) //---------------------------------------------------------------------------------------- { } //---------------------------------------------------------------------------------------- template inline nsFileBufferT::~nsFileBufferT() //---------------------------------------------------------------------------------------- { close(); } //---------------------------------------------------------------------------------------- template inline bool nsFileBufferT::is_open() const //---------------------------------------------------------------------------------------- { NS_READ_LOCK(_mutex); return bool(mFileDesc); // in case it is typedefed to int } //---------------------------------------------------------------------------------------- template nsFileBufferT* nsFileBufferT::open( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- { if (mFileDesc) return 0; NS_WRITE_LOCK(_mutex); mFileDesc = nsFileStreamHelpers::open(inFile, mode, accessMode); if (!mFileDesc) return 0; mode_ = mode; return this; } // nsFileBufferT::open //---------------------------------------------------------------------------------------- template nsFileBufferT* nsFileBufferT::close() //---------------------------------------------------------------------------------------- { if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR) return this; NS_WRITE_LOCK(_mutex); return (mFileDesc && PR_Close(mFileDesc) == PR_SUCCESS) ? mFileDesc = 0, this : 0; } //---------------------------------------------------------------------------------------- template inline int nsFileBufferT:: sync() //---------------------------------------------------------------------------------------- { return (mFileDesc ? (int)PR_Sync(mFileDesc) : 0); } //---------------------------------------------------------------------------------------- template inline BASIC_STREAMBUF* nsFileBufferT::setbuf(char_type*, streamsize) //---------------------------------------------------------------------------------------- { return (!mFileDesc) ? 0 : this; } //---------------------------------------------------------------------------------------- template nsFileBufferT::int_type nsFileBufferT::overflow(int_type c) //---------------------------------------------------------------------------------------- { #ifdef NS_EXPLICIT_FUNC_TEMPLATE_ARG const ofacet_type& ft=use_facet(getloc()); #elif defined(XP_PC) const ofacet_type& ft=use_facet(getloc(), (ofacet_type*)0, false); #else const ofacet_type& ft=use_facet(getloc(), (ofacet_type*)0); #endif char_type ch = traits_type::to_char_type(c); if (!mFileDesc) return traits_type::eof(); if (traits_type::eq_int_type(c, traits::eof())) return traits_type::not_eof(c); if (ft.always_noconv()) { PRInt32 bytesWrit1 = PR_Write(mFileDesc, &ch, sizeof(ch)); return bytesWrit1 < sizeof(ch) ? traits::eof() : c; } { // <- sic! state_type fst; const char_type* end; char buf[4]; char* ebuf; result conv; if ((conv=ft.out(fst, &ch, &ch+1, end, buf, buf+3, ebuf))== codecvt_base::noconv) { PRInt32 bytesWrit2 = PR_Write(mFileDesc, &ch, sizeof(ch)); return bytesWrit2 < sizeof(ch) ? traits::eof() : c; } if ((conv==codecvt_base::partial)||(conv==codecvt_base::error)) return traits::eof(); *ebuf=0; PRInt32 bytesWrit3 = strlen(buf); return PR_Write(mFileDesc, buf, bytesWrit3) < bytesWrit3 ? traits_type::eof() : c; } } //---------------------------------------------------------------------------------------- template inline nsFileBufferT::int_type nsFileBufferT::underflow() //---------------------------------------------------------------------------------------- { if (!mFileDesc) return traits_type::eof(); char_type s; PRInt32 request = 1; if (1 != PR_Read(mFileDesc, &s, request)) return traits_type::eof(); PR_Seek(mFileDesc, -1, PR_SEEK_CUR); return (int_type)s; } //---------------------------------------------------------------------------------------- template streamsize nsFileBufferT::xsputn(const char_type* s, streamsize n) //---------------------------------------------------------------------------------------- { #ifdef NS_EXPLICIT_FUNC_TEMPLATE_ARG const ofacet_type& ft=use_facet(loc); #elif defined(XP_PC) const ofacet_type& ft=use_facet(getloc(), (ofacet_type*)0, false); #else const ofacet_type& ft=use_facet(getloc(), (ofacet_type*)0); #endif if (!mFileDesc || !n) return 0; if (ft.always_noconv()) { PRInt32 bytesWrit1 = PR_Write(mFileDesc, s, sizeof(char) * size_t(n)); return bytesWrit1 < 0 ? 0 : (streamsize)bytesWrit1; } { // <- sic! state_type fst; const char_type* end; char buf[8]; char* ebuf; result conv; #ifdef NS_EXPLICIT_FUNC_TEMPLATE_ARG if ((conv=use_facet(getloc()). #elif defined(XP_PC) if ((conv=use_facet(getloc(), (ofacet_type*)0, false). #else if ((conv=use_facet(getloc(), (ofacet_type*)0). #endif out(fst, s, s+n, end, buf, buf+7, ebuf))==codecvt_base::noconv) return (streamsize)PR_Write(mFileDesc, s, sizeof(char) * size_t(n)); if ((conv==codecvt_base::partial) ||(conv==codecvt_base::error)) return 0; *ebuf=0; PRInt32 bytesWrit2 = strlen(buf); bytesWrit2 = PR_Write(mFileDesc, buf, bytesWrit2); return bytesWrit2 < 0 ? 0 : streamsize(bytesWrit2 / sizeof(char_type)); } } //---------------------------------------------------------------------------------------- template inline nsFileBufferT::int_type nsFileBufferT::pbackfail(int_type c) //---------------------------------------------------------------------------------------- { if (!mFileDesc) return traits_type::eof(); if (PR_Seek(mFileDesc, -1, PR_SEEK_CUR) < 0) return traits_type::eof(); return (traits::eq_int_type(c, traits_type::eof())) ? traits::not_eof(c) : c; } //---------------------------------------------------------------------------------------- template inline nsFileBufferT::int_type nsFileBufferT::uflow() //---------------------------------------------------------------------------------------- { if (!mFileDesc) return traits_type::eof(); char_type s; if (1 != PR_Read(mFileDesc, &s, 1)) // attempt to read 1 byte, confirm 1 byte return traits_type::eof(); return (int_type)s; } //---------------------------------------------------------------------------------------- template inline streamsize nsFileBufferT::xsgetn(char_type* s, streamsize n) //---------------------------------------------------------------------------------------- { return mFileDesc ? (streamsize)PR_Read(mFileDesc, s, sizeof(char) * size_t(n)) : 0; } //---------------------------------------------------------------------------------------- template inline void nsFileBufferT::imbue(const locale& loc_arg) //---------------------------------------------------------------------------------------- { #ifdef XP_MAC loc = loc_arg; #endif } //---------------------------------------------------------------------------------------- template inline streamsize nsFileBufferT::showmanyc() //---------------------------------------------------------------------------------------- { return (streamsize)PR_Available(mFileDesc); } //---------------------------------------------------------------------------------------- template nsFileBufferT::pos_type nsFileBufferT::seekoff( off_type off, IOS_BASE::seekdir way, IOS_BASE::openmode /* which */) //---------------------------------------------------------------------------------------- { if (!mFileDesc || ((way&IOS_BASE::beg) && off<0) || ((way&IOS_BASE::end) && off > 0)) return pos_type(-1); PRSeekWhence poseek = PR_SEEK_CUR; switch (way) { case IOS_BASE::beg : poseek= PR_SEEK_SET; break; case IOS_BASE::end : poseek= PR_SEEK_END; break; } PRInt32 position = PR_Seek(mFileDesc, off, poseek); if (position < 0) return pos_type(-1); return pos_type(position); } //---------------------------------------------------------------------------------------- template nsFileBufferT::pos_type nsFileBufferT::seekpos(pos_type sp, IOS_BASE::openmode) //---------------------------------------------------------------------------------------- { if (!mFileDesc || sp==pos_type(-1)) return -1; #if defined(XP_PC) PRInt32 position = sp; #else PRInt32 position = sp.offset(); #endif position = PR_Seek(mFileDesc, position, PR_SEEK_SET); if (position < 0) return pos_type(-1); return position; } //======================================================================================== // Implementation of nsInputFileStreamT //======================================================================================== //---------------------------------------------------------------------------------------- template inline nsInputFileStreamT::nsInputFileStreamT() : basic_istream(&mBuffer) //---------------------------------------------------------------------------------------- { // already inited } //---------------------------------------------------------------------------------------- template inline nsInputFileStreamT::nsInputFileStreamT( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- : basic_istream(&mBuffer) { // already inited if (!mBuffer.open(inFile, openmode(mode|in), accessMode)) setstate(failbit); } //---------------------------------------------------------------------------------------- template inline nsInputFileStreamT::~nsInputFileStreamT() //---------------------------------------------------------------------------------------- { } //---------------------------------------------------------------------------------------- template inline nsFileBufferT* nsInputFileStreamT::rdbuf() const //---------------------------------------------------------------------------------------- { return (nsFileBufferT*)&mBuffer; } //---------------------------------------------------------------------------------------- template inline bool nsInputFileStreamT:: is_open() //---------------------------------------------------------------------------------------- { return mBuffer.is_open(); } //---------------------------------------------------------------------------------------- template inline void nsInputFileStreamT::open( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- { if (!mBuffer.open(inFile, openmode(mode|in), accessMode)) setstate(failbit); } //---------------------------------------------------------------------------------------- template inline void nsInputFileStreamT::close() //---------------------------------------------------------------------------------------- { if (!mBuffer.close()) setstate(failbit); } //======================================================================================== // Implementation of nsOutputFileStreamT //======================================================================================== //---------------------------------------------------------------------------------------- template inline nsOutputFileStreamT::nsOutputFileStreamT() : basic_ostream(&mBuffer) //---------------------------------------------------------------------------------------- { // already inited } //---------------------------------------------------------------------------------------- template nsOutputFileStreamT::nsOutputFileStreamT( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- : basic_ostream(&mBuffer) { // already inited if (!mBuffer.open(inFile, openmode(mode|out), accessMode)) setstate(failbit); } //---------------------------------------------------------------------------------------- template inline nsOutputFileStreamT::~nsOutputFileStreamT() //---------------------------------------------------------------------------------------- { } //---------------------------------------------------------------------------------------- template inline nsFileBufferT* nsOutputFileStreamT::rdbuf() const //---------------------------------------------------------------------------------------- { return (nsFileBufferT*)&mBuffer; } //---------------------------------------------------------------------------------------- template inline bool nsOutputFileStreamT:: is_open() //---------------------------------------------------------------------------------------- { return mBuffer.is_open(); } //---------------------------------------------------------------------------------------- template inline void nsOutputFileStreamT::open( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- { if (!mBuffer.open(inFile, openmode(mode | out), accessMode)) setstate(failbit); } //---------------------------------------------------------------------------------------- template inline void nsOutputFileStreamT:: close() //---------------------------------------------------------------------------------------- { if (!mBuffer.close()) setstate(failbit); } //======================================================================================== template class nsIOFileStreamT : public basic_iostream //======================================================================================== { typedef nsFileBufferT filebuf_type; public: typedef charT char_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; typedef typename traits::int_type int_type; typedef traits traits_type; nsIOFileStreamT(); explicit nsIOFileStreamT( const nsFilePath& inFile, IOS_BASE::openmode mode = IOS_BASE::in|IOS_BASE::out, PRIntn accessMode = 0x00600); virtual ~nsIOFileStreamT(); filebuf_type* rdbuf() const; inline bool is_open(); inline void open( const nsFilePath& inFile, IOS_BASE::openmode mode = IOS_BASE::in|IOS_BASE::out, PRIntn accessMode = 0x00600); inline void close(); private: filebuf_type mBuffer; }; // class nsIOFileStreamT //======================================================================================== // Implementation of nsIOFileStream //======================================================================================== //---------------------------------------------------------------------------------------- template inline nsIOFileStreamT::nsIOFileStreamT() //---------------------------------------------------------------------------------------- : mBuffer(), basic_iostream(&mBuffer) { // already inited } //---------------------------------------------------------------------------------------- template inline nsIOFileStreamT::nsIOFileStreamT( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- : mBuffer(), basic_iostream(&mBuffer) { // already inited if (!mBuffer.open(inFile, mode, accessMode)) setstate(failbit); } template inline nsIOFileStreamT::~nsIOFileStreamT() { } //---------------------------------------------------------------------------------------- template inline nsFileBufferT* nsIOFileStreamT::rdbuf() const //---------------------------------------------------------------------------------------- { return (nsFileBufferT*)&mBuffer; } //---------------------------------------------------------------------------------------- template inline bool nsIOFileStreamT::is_open() //---------------------------------------------------------------------------------------- { return mBuffer.is_open(); } //---------------------------------------------------------------------------------------- template inline void nsIOFileStreamT::open( const nsFilePath& inFile, IOS_BASE::openmode mode, PRIntn accessMode) //---------------------------------------------------------------------------------------- { if (!mBuffer.open(inFile, mode, accessMode)) setstate(failbit); } //---------------------------------------------------------------------------------------- template inline void nsIOFileStreamT::close() //---------------------------------------------------------------------------------------- { if (!mBuffer.close()) setstate(failbit); } //======================================================================================== // Specializations of the stream templates //======================================================================================== typedef nsFileBufferT > nsFileBuffer; typedef nsInputFileStreamT > nsInputFileStream; typedef nsOutputFileStreamT > nsOutputFileStream; typedef nsIOFileStreamT > nsIOFileStream; #ifdef NS_USING_WIDE_CHAR typedef nsFileBufferT > nsWideFileBuffer; typedef nsInputFileStreamT > nsWideInputFileStream; typedef nsOutputFileStreamT > nsWideOutputFileStream; typedef nsIOFileStreamT > nsWideIOFileStream; #endif // NS_USING_WIDE_CHAR #endif /* _FILESTREAM_H_ */