ITK  4.1.0
Insight Segmentation and Registration Toolkit
itkInternationalizationIOHelpers.h
Go to the documentation of this file.
00001 /*=========================================================================
00002  *
00003  *  Copyright Insight Software Consortium
00004  *
00005  *  Licensed under the Apache License, Version 2.0 (the "License");
00006  *  you may not use this file except in compliance with the License.
00007  *  You may obtain a copy of the License at
00008  *
00009  *         http://www.apache.org/licenses/LICENSE-2.0.txt
00010  *
00011  *  Unless required by applicable law or agreed to in writing, software
00012  *  distributed under the License is distributed on an "AS IS" BASIS,
00013  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  *  See the License for the specific language governing permissions and
00015  *  limitations under the License.
00016  *
00017  *=========================================================================*/
00018 #ifndef __itkInternationalizationIOHelpers_h
00019 #define __itkInternationalizationIOHelpers_h
00020 
00021 // This header provides some helper functions to deal with unicode filenames
00022 // It is mainly directed towards being able to use utf-8 encoded filenames
00023 // on windows.
00024 // This should help better dealing with internationalization (a.k.a i18n)
00025 
00026 #include "itkMacro.h"
00027 #include "itkIOConfigure.h"
00028 
00029 #ifdef ITK_HAVE_UNISTD_H
00030 #include <unistd.h> // for unlink
00031 #else
00032 #include <io.h>
00033 #endif
00034 
00035 #include <stdio.h>
00036 #include <fcntl.h>
00037 #include <iostream>
00038 #include <string>
00039 #include <sys/stat.h>
00040 
00041 // Find out how to handle unicode filenames on windows:
00042 // * VS>=8.0 has _wopen and _wfopen and can open a (i/o)fstream using a wide
00043 // string
00044 // * VS7.x and MinGW have _wopen and _wfopen but cannot open a
00045 //   (i/o)fstream using a wide string. They can however compile fdstream
00046 
00047 #if defined( ITK_SUPPORTS_WCHAR_T_FILENAME_CSTYLEIO ) \
00048   && ( defined( ITK_SUPPORTS_WCHAR_T_FILENAME_IOSTREAMS_CONSTRUCTORS ) || defined( ITK_SUPPORTS_FDSTREAM_HPP ) )
00049 #define LOCAL_USE_WIN32_WOPEN 1
00050 #include <windows.h> // required by winnls.h
00051 #include <winnls.h>  // for MultiByteToWideChar
00052 #else
00053 #define LOCAL_USE_WIN32_WOPEN 0
00054 #endif
00055 
00056 #if ( LOCAL_USE_WIN32_WOPEN && defined( ITK_SUPPORTS_WCHAR_T_FILENAME_IOSTREAMS_CONSTRUCTORS ) ) \
00057   || ( !LOCAL_USE_WIN32_WOPEN )
00058 #define LOCAL_USE_FDSTREAM 0
00059 #include <fstream>
00060 #else
00061 #define LOCAL_USE_FDSTREAM 1
00062 #include "itkfdstream/fdstream.hpp"
00063 #endif
00064 
00065 namespace itk
00066 {
00067 namespace i18n
00068 {
00069 // Check if the string is correctly encoded
00070 #if LOCAL_USE_WIN32_WOPEN
00071 inline bool IsStringEncodingValid(const std::string & str)
00072 {
00073   // Check if the string is really encoded in utf-8 using windows API
00074   // MultiByteToWideChar returns 0 if there was a problem during conversion
00075   // when given the MB_ERR_INVALID_CHARS flag
00076   const int utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(),
00077                                              static_cast< int >( str.length() ), 0, 0);
00078 
00079   return ( utf16_size != 0 );
00080 }
00081 
00082 #else
00083 inline bool IsStringEncodingValid( const std::string & itkNotUsed(str) )
00084 {
00085   return true;
00086 }
00087 
00088 #endif
00089 
00090 #if LOCAL_USE_WIN32_WOPEN
00091 // Convert a utf8 encoded std::string to a utf16 encoded wstring on windows
00092 inline std::wstring Utf8StringToWString(const std::string & str)
00093 {
00094   // We do not set the MB_ERR_INVALID_CHARS to do an approximate conversion when
00095   // non
00096   // utf8 characters are found. An alternative would be to throw an exception
00097 
00098   // First get the size
00099   const int utf16_size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(),
00100                                              static_cast< int >( str.length() ), 0, 0);
00101 
00102   // Now do the conversion
00103   std::wstring wstr;
00104 
00105   wstr.resize(utf16_size);
00106   MultiByteToWideChar(CP_UTF8, 0, str.c_str(),
00107                       static_cast< int >( str.length() ), &wstr[0], utf16_size);
00108 
00109   return wstr;
00110 }
00111 
00112 #endif
00113 
00114 // Get a file descriptor from a filename (using utf8 to wstring
00115 // on windows if requested) without specifying any specific permissions
00116 inline int I18nOpen(const std::string & str, const int & flags)
00117 {
00118 #if LOCAL_USE_WIN32_WOPEN
00119   // mingw has _wopen
00120   // Convert to utf16
00121   const std::wstring str_utf16 = Utf8StringToWString(str);
00122   return _wopen(str_utf16.c_str(), flags);
00123 #else
00124   return open(str.c_str(), flags);
00125 #endif
00126 }
00127 
00128 // Get a file descriptor from a filename (using utf8 to wstring
00129 // on windows if requested)
00130 inline int I18nOpen(const std::string & str, const int & flags, const int & mode)
00131 {
00132 #if LOCAL_USE_WIN32_WOPEN
00133   // mingw has _wopen
00134   // Convert to utf16
00135   const std::wstring str_utf16 = Utf8StringToWString(str);
00136   return _wopen(str_utf16.c_str(), flags, mode);
00137 #else
00138   return open(str.c_str(), flags, mode);
00139 #endif
00140 }
00141 
00142 // Reading wrapper around I18nOpen to avoid explicitely specifying the flags
00143 inline int I18nOpenForReading(const std::string & str)
00144 {
00145 #if LOCAL_USE_WIN32_WOPEN
00146   return I18nOpen(str, _O_RDONLY | _O_BINARY);
00147 #else
00148   return I18nOpen(str, O_RDONLY);
00149 #endif
00150 }
00151 
00152 // Writing wrapper around I18nOpen to avoid explicitely specifying the flags
00153 inline int I18nOpenForWriting(const std::string & str, const bool append = false)
00154 {
00155 #if LOCAL_USE_WIN32_WOPEN
00156   if ( !append ) { return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_BINARY, _S_IREAD | _S_IWRITE); }
00157   else { return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY, _S_IREAD | _S_IWRITE); }
00158 #else
00159   if ( !append ) { return I18nOpen(str, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE); }
00160   else { return I18nOpen(str, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE); }
00161 #endif
00162 }
00163 
00164 // Get a FILE * pointer from a filename (using utf8 to wstring
00165 // on windows if requested)
00166 inline FILE * I18nFopen(const std::string & str, const std::string & mode)
00167 {
00168 #if LOCAL_USE_WIN32_WOPEN
00169   // Convert to utf16
00170   const std::wstring str_utf16 = Utf8StringToWString(str);
00171   const std::wstring mode_utf16 = Utf8StringToWString(mode);
00172   return _wfopen( str_utf16.c_str(), mode_utf16.c_str() );
00173 #else
00174   return fopen( str.c_str(), mode.c_str() );
00175 #endif
00176 }
00177 
00178 #if LOCAL_USE_FDSTREAM
00179 class I18nOfstream:public std::ostream
00180 {
00181 public:
00182   I18nOfstream(const char *str,
00183                std::ios_base::openmode mode = std::ios_base::out):
00184     std::ostream(0),
00185     m_fd( I18nOpenForWriting(str, ( mode & std::ios::app ) ? true:false) ),
00186     m_buf(m_fd)
00187   {
00189     this->rdbuf(&m_buf);
00190   }
00191 
00192   ~I18nOfstream() { this->close(); }
00193 
00194   bool is_open() { return ( m_fd != -1 ); }
00195 
00196   void close()
00197   {
00198     if ( m_fd != -1 ) { ::close(m_fd); }
00199     m_fd = -1;
00200   }
00201 
00202 private:
00203   int           m_fd;
00204   itk::fdoutbuf m_buf;
00205 };
00206 
00207 class I18nIfstream:public std::istream
00208 {
00209 public:
00210   I18nIfstream(const char *str,
00211                std::ios_base::openmode mode = std::ios_base::in):
00212     std::istream(0),
00213     m_fd( I18nOpenForReading(str) ),
00214     m_buf(m_fd)
00215   {
00217     (void) mode;
00218     this->rdbuf(&m_buf);
00219   }
00220 
00221   ~I18nIfstream() { this->close(); }
00222 
00223   bool is_open() { return ( m_fd != -1 ); }
00224 
00225   void close()
00226   {
00227     if ( m_fd != -1 ) { ::close(m_fd); }
00228     m_fd = -1;
00229   }
00230 
00231 private:
00232   int          m_fd;
00233   itk::fdinbuf m_buf;
00234 };
00235 #elif LOCAL_USE_WIN32_WOPEN
00236 class I18nOfstream:public std::ofstream
00237 {
00238 public:
00239   I18nOfstream(const char *str, std::ios_base::openmode mode = std::ios_base::out):
00240     std::ofstream(Utf8StringToWString(str).c_str(), mode)
00241   {}
00242 };
00243 
00244 class I18nIfstream:public std::ifstream
00245 {
00246 public:
00247   I18nIfstream(const char *str, std::ios_base::openmode mode = std::ios_base::in):
00248     std::ifstream(Utf8StringToWString(str).c_str(), mode)
00249   {}
00250 };
00251 #else
00252 typedef std::ofstream I18nOfstream;
00253 typedef std::ifstream I18nIfstream;
00254 #endif
00255 } // end namespace
00256 } // end namespace
00257 
00258 #undef LOCAL_USE_WIN32_WOPEN
00259 #undef LOCAL_USE_FDSTREAM
00260 
00261 #endif  /* __itkInternationalizationIOHelpers_h */
00262