ITK  6.0.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
65namespace itk
66{
67namespace i18n
68{
69// Check if the string is correctly encoded
70#if LOCAL_USE_WIN32_WOPEN
71inline bool
72IsStringEncodingValid(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
84inline bool
85IsStringEncodingValid(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
94inline std::wstring
95Utf8StringToWString(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
117inline int
118I18nOpen(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)
132inline int
133I18nOpen(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
146inline int
147I18nOpenForReading(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
157inline int
158I18nOpenForWriting(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)
192inline FILE *
193I18nFopen(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
206class I18nOfstream : public std::ostream
207{
208public:
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
236private:
237 int m_fd;
238 itk::fdoutbuf m_buf;
239};
240
241class I18nIfstream : public std::istream
242{
243public:
244 I18nIfstream(const char * str, std::ios_base::openmode itkNotused(mode) = std::ios_base::in)
245 : std::istream(0)
246 , m_fd(I18nOpenForReading(str))
247 , m_buf(m_fd)
248 {
250 this->rdbuf(&m_buf);
251 }
252
253 ~I18nIfstream() { this->close(); }
254
255 bool
256 is_open()
257 {
258 return (m_fd != -1);
259 }
260
261 void
262 close()
263 {
264 if (m_fd != -1)
265 {
266 ::close(m_fd);
267 }
268 m_fd = -1;
269 }
270
271private:
272 int m_fd;
273 itk::fdinbuf m_buf;
274};
275#elif LOCAL_USE_WIN32_WOPEN
276class I18nOfstream : public std::ofstream
277{
278public:
279 I18nOfstream(const char * str, std::ios_base::openmode mode = std::ios_base::out)
280 : std::ofstream(Utf8StringToWString(str).c_str(), mode)
281 {}
282};
283
284class I18nIfstream : public std::ifstream
285{
286public:
287 I18nIfstream(const char * str, std::ios_base::openmode mode = std::ios_base::in)
288 : std::ifstream(Utf8StringToWString(str).c_str(), mode)
289 {}
290};
291#else
292using I18nOfstream = std::ofstream;
293using I18nIfstream = std::ifstream;
294#endif
295} // namespace i18n
296} // namespace itk
297
298#undef LOCAL_USE_WIN32_WOPEN
299#undef LOCAL_USE_FDSTREAM
300
301#endif /* itkInternationalizationIOHelpers_h */
int I18nOpen(const std::string &str, const int flags)
int I18nOpenForReading(const std::string &str)
bool IsStringEncodingValid(const std::string &)
int I18nOpenForWriting(const std::string &str, const bool append=false)
FILE * I18nFopen(const std::string &str, const std::string &mode)
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
STL namespace.