ITK  5.4.0
Insight Toolkit
itkInternationalizationIOHelpers.h
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright NumFOCUS
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  * https://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 #include "ITKIOImageBaseExport.h"
21 
22 // This header provides some helper functions to deal with unicode filenames
23 // It is mainly directed towards being able to use utf-8 encoded filenames
24 // on windows.
25 // This should help better dealing with internationalization (a.k.a i18n)
26 
27 #include "itkMacro.h"
28 #include "itkIOConfigure.h"
29 
30 #ifdef ITK_HAVE_UNISTD_H
31 # include <unistd.h> // for unlink
32 #else
33 # include <io.h>
34 #endif
35 
36 #include <cstdio>
37 #include <fcntl.h>
38 #include <iostream>
39 #include <string>
40 #include <sys/stat.h>
41 
42 // Find out how to handle unicode filenames on windows:
43 // * VS>=8.0 has _wopen and _wfopen and can open a (i/o)fstream using a wide
44 // string
45 // * VS7.x and MinGW have _wopen and _wfopen but cannot open a
46 // (i/o)fstream using a wide string. They can however compile fdstream
47 
48 #if defined(ITK_SUPPORTS_WCHAR_T_FILENAME_CSTYLEIO) && \
49  (defined(ITK_SUPPORTS_WCHAR_T_FILENAME_IOSTREAMS_CONSTRUCTORS) || defined(ITK_SUPPORTS_FDSTREAM_HPP))
50 # define LOCAL_USE_WIN32_WOPEN 1
51 # include <windows.h> // required by winnls.h
52 # include <winnls.h> // for MultiByteToWideChar
53 #else
54 # define LOCAL_USE_WIN32_WOPEN 0
55 #endif
56 
57 #if (LOCAL_USE_WIN32_WOPEN && defined(ITK_SUPPORTS_WCHAR_T_FILENAME_IOSTREAMS_CONSTRUCTORS)) || (!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.hxx"
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
72 IsStringEncodingValid(const std::string & str)
73 {
74  // Check if the string is really encoded in utf-8 using windows API
75  // MultiByteToWideChar returns 0 if there was a problem during conversion
76  // when given the MB_ERR_INVALID_CHARS flag
77  const int utf16_size =
78  MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), static_cast<int>(str.length()), nullptr, 0);
79 
80  return (utf16_size != 0);
81 }
82 
83 #else
84 inline bool
85 IsStringEncodingValid(const std::string & itkNotUsed(str))
86 {
87  return true;
88 }
89 
90 #endif
91 
92 #if LOCAL_USE_WIN32_WOPEN
93 // Convert a utf8 encoded std::string to a utf16 encoded wstring on windows
94 inline std::wstring
95 Utf8StringToWString(const std::string & str)
96 {
97  // We do not set the MB_ERR_INVALID_CHARS to do an approximate conversion when
98  // non
99  // utf8 characters are found. An alternative would be to throw an exception
100 
101  // First get the size
102  const int utf16_size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast<int>(str.length()), nullptr, 0);
103 
104  // Now do the conversion
105  std::wstring wstr;
106 
107  wstr.resize(utf16_size);
108  MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast<int>(str.length()), &wstr[0], utf16_size);
109 
110  return wstr;
111 }
112 
113 #endif
114 
115 // Get a file descriptor from a filename (using utf8 to wstring
116 // on windows if requested) without specifying any specific permissions
117 inline int
118 I18nOpen(const std::string & str, const int flags)
119 {
120 #if LOCAL_USE_WIN32_WOPEN
121  // mingw has _wopen
122  // Convert to utf16
123  const std::wstring str_utf16 = Utf8StringToWString(str);
124  return _wopen(str_utf16.c_str(), flags);
125 #else
126  return open(str.c_str(), flags);
127 #endif
128 }
129 
130 // Get a file descriptor from a filename (using utf8 to wstring
131 // on windows if requested)
132 inline int
133 I18nOpen(const std::string & str, const int flags, const int mode)
134 {
135 #if LOCAL_USE_WIN32_WOPEN
136  // mingw has _wopen
137  // Convert to utf16
138  const std::wstring str_utf16 = Utf8StringToWString(str);
139  return _wopen(str_utf16.c_str(), flags, mode);
140 #else
141  return open(str.c_str(), flags, mode);
142 #endif
143 }
144 
145 // Reading wrapper around I18nOpen to avoid explicitly specifying the flags
146 inline int
147 I18nOpenForReading(const std::string & str)
148 {
149 #if LOCAL_USE_WIN32_WOPEN
150  return I18nOpen(str, _O_RDONLY | _O_BINARY);
151 #else
152  return I18nOpen(str, O_RDONLY);
153 #endif
154 }
155 
156 // Writing wrapper around I18nOpen to avoid explicitly specifying the flags
157 inline int
158 I18nOpenForWriting(const std::string & str, const bool append = false)
159 {
160 #if LOCAL_USE_WIN32_WOPEN
161  if (!append)
162  {
163  return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_BINARY, _S_IREAD | _S_IWRITE);
164  }
165  else
166  {
167  return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY, _S_IREAD | _S_IWRITE);
168  }
169 #elif S_IRUSR
170  if (!append)
171  {
172  return I18nOpen(str, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
173  }
174  else
175  {
176  return I18nOpen(str, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
177  }
178 #else
179  if (!append)
180  {
181  return I18nOpen(str, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
182  }
183  else
184  {
185  return I18nOpen(str, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE);
186  }
187 #endif
188 }
189 
190 // Get a FILE * pointer from a filename (using utf8 to wstring
191 // on windows if requested)
192 inline FILE *
193 I18nFopen(const std::string & str, const std::string & mode)
194 {
195 #if LOCAL_USE_WIN32_WOPEN
196  // Convert to utf16
197  const std::wstring str_utf16 = Utf8StringToWString(str);
198  const std::wstring mode_utf16 = Utf8StringToWString(mode);
199  return _wfopen(str_utf16.c_str(), mode_utf16.c_str());
200 #else
201  return fopen(str.c_str(), mode.c_str());
202 #endif
203 }
204 
205 #if LOCAL_USE_FDSTREAM
206 class I18nOfstream : public std::ostream
207 {
208 public:
209  I18nOfstream(const char * str, std::ios_base::openmode mode = std::ios_base::out)
210  : std::ostream(0)
211  , m_fd(I18nOpenForWriting(str, (mode & std::ios::app) ? true : false))
212  , m_buf(m_fd)
213  {
215  this->rdbuf(&m_buf);
216  }
217 
218  ~I18nOfstream() { this->close(); }
219 
220  bool
221  is_open()
222  {
223  return (m_fd != -1);
224  }
225 
226  void
227  close()
228  {
229  if (m_fd != -1)
230  {
231  ::close(m_fd);
232  }
233  m_fd = -1;
234  }
235 
236 private:
237  int m_fd;
238  itk::fdoutbuf m_buf;
239 };
240 
241 class I18nIfstream : public std::istream
242 {
243 public:
244  I18nIfstream(const char * str, std::ios_base::openmode mode = std::ios_base::in)
245  : std::istream(0)
246  , m_fd(I18nOpenForReading(str))
247  , m_buf(m_fd)
248  {
250  (void)mode;
251  this->rdbuf(&m_buf);
252  }
253 
254  ~I18nIfstream() { this->close(); }
255 
256  bool
257  is_open()
258  {
259  return (m_fd != -1);
260  }
261 
262  void
263  close()
264  {
265  if (m_fd != -1)
266  {
267  ::close(m_fd);
268  }
269  m_fd = -1;
270  }
271 
272 private:
273  int m_fd;
274  itk::fdinbuf m_buf;
275 };
276 #elif LOCAL_USE_WIN32_WOPEN
277 class I18nOfstream : public std::ofstream
278 {
279 public:
280  I18nOfstream(const char * str, std::ios_base::openmode mode = std::ios_base::out)
281  : std::ofstream(Utf8StringToWString(str).c_str(), mode)
282  {}
283 };
284 
285 class I18nIfstream : public std::ifstream
286 {
287 public:
288  I18nIfstream(const char * str, std::ios_base::openmode mode = std::ios_base::in)
289  : std::ifstream(Utf8StringToWString(str).c_str(), mode)
290  {}
291 };
292 #else
293 using I18nOfstream = std::ofstream;
294 using I18nIfstream = std::ifstream;
295 #endif
296 } // namespace i18n
297 } // namespace itk
298 
299 #undef LOCAL_USE_WIN32_WOPEN
300 #undef LOCAL_USE_FDSTREAM
301 
302 #endif /* itkInternationalizationIOHelpers_h */
itk::i18n::I18nOpen
int I18nOpen(const std::string &str, const int flags)
Definition: itkInternationalizationIOHelpers.h:118
itk::i18n::IsStringEncodingValid
bool IsStringEncodingValid(const std::string &)
Definition: itkInternationalizationIOHelpers.h:85
itk::i18n::I18nOpenForWriting
int I18nOpenForWriting(const std::string &str, const bool append=false)
Definition: itkInternationalizationIOHelpers.h:158
itkMacro.h
itk::i18n::I18nOpenForReading
int I18nOpenForReading(const std::string &str)
Definition: itkInternationalizationIOHelpers.h:147
itk::i18n::I18nFopen
FILE * I18nFopen(const std::string &str, const std::string &mode)
Definition: itkInternationalizationIOHelpers.h:193
itk
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
Definition: itkAnnulusOperator.h:24
itk::i18n::I18nIfstream
std::ifstream I18nIfstream
Definition: itkInternationalizationIOHelpers.h:294
itk::i18n::I18nOfstream
std::ofstream I18nOfstream
Definition: itkInternationalizationIOHelpers.h:293