]> git.lyx.org Git - features.git/commitdiff
Avoid encoding changes of open streams if possible
authorGeorg Baum <baum@lyx.org>
Sun, 31 Jan 2016 11:49:17 +0000 (12:49 +0100)
committerGeorg Baum <baum@lyx.org>
Sun, 31 Jan 2016 11:49:17 +0000 (12:49 +0100)
Changing the codecvt_facet of a file stream after the file has been opened
does not work with clang on OS X. Therefore we avoid it if possible (i. e. the
new encoding is the same as the old one).

src/support/docstream.cpp
src/support/docstream.h

index b07ac56a320dea157d5723e8214ea4a9aac1e12c..e33dffc3c0da0bf6621021948089475b03926415 100644 (file)
@@ -88,6 +88,7 @@ public:
                } else
                        out_cd_ = (iconv_t)(-1);
        }
+       string const & encoding() const { return encoding_; }
 protected:
        virtual ~iconv_codecvt_facet()
        {
@@ -375,37 +376,51 @@ odocstream & operator<<(odocstream & os, SetEnc e)
        if (has_facet<iconv_codecvt_facet>(os.rdbuf()->getloc())) {
                // This stream must be a file stream, since we never imbue
                // any other stream with a locale having a iconv_codecvt_facet.
+               iconv_codecvt_facet const & facet =
+                       use_facet<iconv_codecvt_facet>(os.rdbuf()->getloc());
+
+               // FIXME Changing the codecvt facet of an open file is allowed,
+               // but unsafe for facets that use internal state (see the thread
+               // "iostreams: Does imbue() need to be called before open()?"
+               // in comp.std.c++.
+               // Currently it seems to work with gcc and MSVC, but not with
+               // clang on OS X.
+               // Avoid imbueing with the same encoding again if possible.
+               if (facet.encoding() == e.encoding)
+                       return os;
+
                // Flush the stream so that all pending output is written
                // with the old encoding.
                os.flush();
+
                locale locale(os.rdbuf()->getloc(),
                        new iconv_codecvt_facet(e.encoding, ios_base::out));
-               // FIXME Does changing the codecvt facet of an open file
-               // stream always work? It does with gcc 4.1, but I have read
-               // somewhere that it does not with MSVC.
-               // What does the standard say?
                os.imbue(locale);
        }
        return os;
 }
 
 
-//CHECKME: I just copied the code above, and have no idea whether it
-//is correct... (JMarc)
 idocstream & operator<<(idocstream & is, SetEnc e)
 {
        if (has_facet<iconv_codecvt_facet>(is.rdbuf()->getloc())) {
                // This stream must be a file stream, since we never imbue
                // any other stream with a locale having a iconv_codecvt_facet.
-               // Flush the stream so that all pending output is written
-               // with the old encoding.
-               //is.flush();
+               iconv_codecvt_facet const & facet =
+                       use_facet<iconv_codecvt_facet>(is.rdbuf()->getloc());
+
+               // FIXME Changing the codecvt facet of an open file is allowed,
+               // but unsafe for facets that use internal state (see the thread
+               // "iostreams: Does imbue() need to be called before open()?"
+               // in comp.std.c++.
+               // Currently it seems to work with gcc and MSVC, but not with
+               // clang on OS X.
+               // Avoid imbueing with the same encoding again if possible.
+               if (facet.encoding() == e.encoding)
+                       return is;
+
                locale locale(is.rdbuf()->getloc(),
                        new iconv_codecvt_facet(e.encoding, ios_base::in));
-               // FIXME Does changing the codecvt facet of an open file
-               // stream always work? It does with gcc 4.1, but I have read
-               // somewhere that it does not with MSVC.
-               // What does the standard say?
                is.imbue(locale);
        }
        return is;
index 108d00e0f63d243a24a329d601d792f708bb1523..a6197cccd6789812760a90238d5a97dee56fcefc 100644 (file)
@@ -42,6 +42,8 @@ typedef std::basic_ostream<char_type> odocstream;
 
 /// File stream for reading UTF8-encoded files with automatic conversion to
 /// UCS4.
+/// Buffering must be switched off if the encoding is changed after
+/// construction by calling rdbuf()->pubsetbuf(0, 0).
 class ifdocstream : public std::basic_ifstream<char_type> {
        typedef std::basic_ifstream<char_type> base;
 public: