ITK  4.2.0
Insight Segmentation and Registration Toolkit
itkInternationalizationIOHelpers.h
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright Insight Software Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef __itkInternationalizationIOHelpers_h
19 #define __itkInternationalizationIOHelpers_h
20 
21 // This header provides some helper functions to deal with unicode filenames
22 // It is mainly directed towards being able to use utf-8 encoded filenames
23 // on windows.
24 // This should help better dealing with internationalization (a.k.a i18n)
25 
26 #include "itkMacro.h"
27 #include "itkIOConfigure.h"
28 
29 #ifdef ITK_HAVE_UNISTD_H
30 #include <unistd.h> // for unlink
31 #else
32 #include <io.h>
33 #endif
34 
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <iostream>
38 #include <string>
39 #include <sys/stat.h>
40 
41 // Find out how to handle unicode filenames on windows:
42 // * VS>=8.0 has _wopen and _wfopen and can open a (i/o)fstream using a wide
43 // string
44 // * VS7.x and MinGW have _wopen and _wfopen but cannot open a
45 // (i/o)fstream using a wide string. They can however compile fdstream
46 
47 #if defined( ITK_SUPPORTS_WCHAR_T_FILENAME_CSTYLEIO ) \
48  && ( defined( ITK_SUPPORTS_WCHAR_T_FILENAME_IOSTREAMS_CONSTRUCTORS ) || defined( ITK_SUPPORTS_FDSTREAM_HPP ) )
49 #define LOCAL_USE_WIN32_WOPEN 1
50 #include <windows.h> // required by winnls.h
51 #include <winnls.h> // for MultiByteToWideChar
52 #else
53 #define LOCAL_USE_WIN32_WOPEN 0
54 #endif
55 
56 #if ( LOCAL_USE_WIN32_WOPEN && defined( ITK_SUPPORTS_WCHAR_T_FILENAME_IOSTREAMS_CONSTRUCTORS ) ) \
57  || ( !LOCAL_USE_WIN32_WOPEN )
58 #define LOCAL_USE_FDSTREAM 0
59 #include <fstream>
60 #else
61 #define LOCAL_USE_FDSTREAM 1
62 #include "itkfdstream/fdstream.hpp"
63 #endif
64 
65 namespace itk
66 {
67 namespace i18n
68 {
69 // Check if the string is correctly encoded
70 #if LOCAL_USE_WIN32_WOPEN
71 inline bool IsStringEncodingValid(const std::string & str)
72 {
73  // Check if the string is really encoded in utf-8 using windows API
74  // MultiByteToWideChar returns 0 if there was a problem during conversion
75  // when given the MB_ERR_INVALID_CHARS flag
76  const int utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(),
77  static_cast< int >( str.length() ), 0, 0);
78 
79  return ( utf16_size != 0 );
80 }
81 
82 #else
83 inline bool IsStringEncodingValid( const std::string & itkNotUsed(str) )
84 {
85  return true;
86 }
87 
88 #endif
89 
90 #if LOCAL_USE_WIN32_WOPEN
91 // Convert a utf8 encoded std::string to a utf16 encoded wstring on windows
92 inline std::wstring Utf8StringToWString(const std::string & str)
93 {
94  // We do not set the MB_ERR_INVALID_CHARS to do an approximate conversion when
95  // non
96  // utf8 characters are found. An alternative would be to throw an exception
97 
98  // First get the size
99  const int utf16_size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(),
100  static_cast< int >( str.length() ), 0, 0);
101 
102  // Now do the conversion
103  std::wstring wstr;
104 
105  wstr.resize(utf16_size);
106  MultiByteToWideChar(CP_UTF8, 0, str.c_str(),
107  static_cast< int >( str.length() ), &wstr[0], utf16_size);
108 
109  return wstr;
110 }
111 
112 #endif
113 
114 // Get a file descriptor from a filename (using utf8 to wstring
115 // on windows if requested) without specifying any specific permissions
116 inline int I18nOpen(const std::string & str, const int & flags)
117 {
118 #if LOCAL_USE_WIN32_WOPEN
119  // mingw has _wopen
120  // Convert to utf16
121  const std::wstring str_utf16 = Utf8StringToWString(str);
122  return _wopen(str_utf16.c_str(), flags);
123 #else
124  return open(str.c_str(), flags);
125 #endif
126 }
127 
128 // Get a file descriptor from a filename (using utf8 to wstring
129 // on windows if requested)
130 inline int I18nOpen(const std::string & str, const int & flags, const int & mode)
131 {
132 #if LOCAL_USE_WIN32_WOPEN
133  // mingw has _wopen
134  // Convert to utf16
135  const std::wstring str_utf16 = Utf8StringToWString(str);
136  return _wopen(str_utf16.c_str(), flags, mode);
137 #else
138  return open(str.c_str(), flags, mode);
139 #endif
140 }
141 
142 // Reading wrapper around I18nOpen to avoid explicitely specifying the flags
143 inline int I18nOpenForReading(const std::string & str)
144 {
145 #if LOCAL_USE_WIN32_WOPEN
146  return I18nOpen(str, _O_RDONLY | _O_BINARY);
147 #else
148  return I18nOpen(str, O_RDONLY);
149 #endif
150 }
151 
152 // Writing wrapper around I18nOpen to avoid explicitely specifying the flags
153 inline int I18nOpenForWriting(const std::string & str, const bool append = false)
154 {
155 #if LOCAL_USE_WIN32_WOPEN
156  if ( !append ) { return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_BINARY, _S_IREAD | _S_IWRITE); }
157  else { return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY, _S_IREAD | _S_IWRITE); }
158 #else
159  if ( !append ) { return I18nOpen(str, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE); }
160  else { return I18nOpen(str, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE); }
161 #endif
162 }
163 
164 // Get a FILE * pointer from a filename (using utf8 to wstring
165 // on windows if requested)
166 inline FILE * I18nFopen(const std::string & str, const std::string & mode)
167 {
168 #if LOCAL_USE_WIN32_WOPEN
169  // Convert to utf16
170  const std::wstring str_utf16 = Utf8StringToWString(str);
171  const std::wstring mode_utf16 = Utf8StringToWString(mode);
172  return _wfopen( str_utf16.c_str(), mode_utf16.c_str() );
173 #else
174  return fopen( str.c_str(), mode.c_str() );
175 #endif
176 }
177 
178 #if LOCAL_USE_FDSTREAM
179 class I18nOfstream:public std::ostream
180 {
181 public:
182  I18nOfstream(const char *str,
183  std::ios_base::openmode mode = std::ios_base::out):
184  std::ostream(0),
185  m_fd( I18nOpenForWriting(str, ( mode & std::ios::app ) ? true:false) ),
186  m_buf(m_fd)
187  {
189  this->rdbuf(&m_buf);
190  }
191 
192  ~I18nOfstream() { this->close(); }
193 
194  bool is_open() { return ( m_fd != -1 ); }
195 
196  void close()
197  {
198  if ( m_fd != -1 ) { ::close(m_fd); }
199  m_fd = -1;
200  }
201 
202 private:
203  int m_fd;
204  itk::fdoutbuf m_buf;
205 };
206 
207 class I18nIfstream:public std::istream
208 {
209 public:
210  I18nIfstream(const char *str,
211  std::ios_base::openmode mode = std::ios_base::in):
212  std::istream(0),
213  m_fd( I18nOpenForReading(str) ),
214  m_buf(m_fd)
215  {
217  (void) mode;
218  this->rdbuf(&m_buf);
219  }
220 
221  ~I18nIfstream() { this->close(); }
222 
223  bool is_open() { return ( m_fd != -1 ); }
224 
225  void close()
226  {
227  if ( m_fd != -1 ) { ::close(m_fd); }
228  m_fd = -1;
229  }
230 
231 private:
232  int m_fd;
233  itk::fdinbuf m_buf;
234 };
235 #elif LOCAL_USE_WIN32_WOPEN
236 class I18nOfstream:public std::ofstream
237 {
238 public:
239  I18nOfstream(const char *str, std::ios_base::openmode mode = std::ios_base::out):
240  std::ofstream(Utf8StringToWString(str).c_str(), mode)
241  {}
242 };
243 
244 class I18nIfstream:public std::ifstream
245 {
246 public:
247  I18nIfstream(const char *str, std::ios_base::openmode mode = std::ios_base::in):
248  std::ifstream(Utf8StringToWString(str).c_str(), mode)
249  {}
250 };
251 #else
252 typedef std::ofstream I18nOfstream;
253 typedef std::ifstream I18nIfstream;
254 #endif
255 } // end namespace
256 } // end namespace
257 
258 #undef LOCAL_USE_WIN32_WOPEN
259 #undef LOCAL_USE_FDSTREAM
260 
261 #endif /* __itkInternationalizationIOHelpers_h */
262