ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
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::i18n
66{
67// Check if the string is correctly encoded
68#if LOCAL_USE_WIN32_WOPEN
69inline bool
70IsStringEncodingValid(const std::string & str)
71{
72 // Check if the string is really encoded in utf-8 using windows API
73 // MultiByteToWideChar returns 0 if there was a problem during conversion
74 // when given the MB_ERR_INVALID_CHARS flag
75 const int utf16_size =
76 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), static_cast<int>(str.length()), nullptr, 0);
77
78 return (utf16_size != 0);
79}
80
81#else
82inline bool
83IsStringEncodingValid(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
92inline std::wstring
93Utf8StringToWString(const std::string & str)
94{
95 // We do not set the MB_ERR_INVALID_CHARS to do an approximate conversion when
96 // non
97 // utf8 characters are found. An alternative would be to throw an exception
98
99 // First get the size
100 const int utf16_size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast<int>(str.length()), nullptr, 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(), static_cast<int>(str.length()), &wstr[0], utf16_size);
107
108 return wstr;
109}
110
111#endif
112
113// Get a file descriptor from a filename (using utf8 to wstring
114// on windows if requested) without specifying any specific permissions
115inline int
116I18nOpen(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)
130inline int
131I18nOpen(const std::string & str, const int flags, const int mode)
132{
133#if LOCAL_USE_WIN32_WOPEN
134 // mingw has _wopen
135 // Convert to utf16
136 const std::wstring str_utf16 = Utf8StringToWString(str);
137 return _wopen(str_utf16.c_str(), flags, mode);
138#else
139 return open(str.c_str(), flags, mode);
140#endif
141}
142
143// Reading wrapper around I18nOpen to avoid explicitly specifying the flags
144inline int
145I18nOpenForReading(const std::string & str)
146{
147#if LOCAL_USE_WIN32_WOPEN
148 return I18nOpen(str, _O_RDONLY | _O_BINARY);
149#else
150 return I18nOpen(str, O_RDONLY);
151#endif
152}
153
154// Writing wrapper around I18nOpen to avoid explicitly specifying the flags
155inline int
156I18nOpenForWriting(const std::string & str, const bool append = false)
157{
158#if LOCAL_USE_WIN32_WOPEN
159 if (!append)
160 {
161 return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_BINARY, _S_IREAD | _S_IWRITE);
162 }
163 else
164 {
165 return I18nOpen(str, _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY, _S_IREAD | _S_IWRITE);
166 }
167#elif S_IRUSR
168 if (!append)
169 {
170 return I18nOpen(str, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
171 }
172
173 return I18nOpen(str, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
174
175#else
176 if (!append)
177 {
178 return I18nOpen(str, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
179 }
180 else
181 {
182 return I18nOpen(str, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE);
183 }
184#endif
185}
186
187// Get a FILE * pointer from a filename (using utf8 to wstring
188// on windows if requested)
189inline FILE *
190I18nFopen(const std::string & str, const std::string & mode)
191{
192#if LOCAL_USE_WIN32_WOPEN
193 // Convert to utf16
194 const std::wstring str_utf16 = Utf8StringToWString(str);
195 const std::wstring mode_utf16 = Utf8StringToWString(mode);
196 return _wfopen(str_utf16.c_str(), mode_utf16.c_str());
197#else
198 return fopen(str.c_str(), mode.c_str());
199#endif
200}
201
202#if LOCAL_USE_FDSTREAM
203class I18nOfstream : public std::ostream
204{
205public:
206 I18nOfstream(const char * str, std::ios_base::openmode mode = std::ios_base::out)
207 : std::ostream(0)
208 , m_fd(I18nOpenForWriting(str, (mode & std::ios::app) ? true : false))
209 , m_buf(m_fd)
210 {
212 this->rdbuf(&m_buf);
213 }
214
215 ~I18nOfstream() { this->close(); }
216
217 bool
218 is_open()
219 {
220 return (m_fd != -1);
221 }
222
223 void
224 close()
225 {
226 if (m_fd != -1)
227 {
228 ::close(m_fd);
229 }
230 m_fd = -1;
231 }
232
233private:
234 int m_fd;
235 itk::fdoutbuf m_buf;
236};
237
238class I18nIfstream : public std::istream
239{
240public:
241 I18nIfstream(const char * str, std::ios_base::openmode itkNotused(mode) = std::ios_base::in)
242 : std::istream(0)
243 , m_fd(I18nOpenForReading(str))
244 , m_buf(m_fd)
245 {
247 this->rdbuf(&m_buf);
248 }
249
250 ~I18nIfstream() { this->close(); }
251
252 bool
253 is_open()
254 {
255 return (m_fd != -1);
256 }
257
258 void
259 close()
260 {
261 if (m_fd != -1)
262 {
263 ::close(m_fd);
264 }
265 m_fd = -1;
266 }
267
268private:
269 int m_fd;
270 itk::fdinbuf m_buf;
271};
272#elif LOCAL_USE_WIN32_WOPEN
273class I18nOfstream : public std::ofstream
274{
275public:
276 I18nOfstream(const char * str, std::ios_base::openmode mode = std::ios_base::out)
277 : std::ofstream(Utf8StringToWString(str).c_str(), mode)
278 {}
279};
280
281class I18nIfstream : public std::ifstream
282{
283public:
284 I18nIfstream(const char * str, std::ios_base::openmode mode = std::ios_base::in)
285 : std::ifstream(Utf8StringToWString(str).c_str(), mode)
286 {}
287};
288#else
289using I18nOfstream = std::ofstream;
290using I18nIfstream = std::ifstream;
291#endif
292} // namespace itk::i18n
293
294
295#undef LOCAL_USE_WIN32_WOPEN
296#undef LOCAL_USE_FDSTREAM
297
298#endif /* itkInternationalizationIOHelpers_h */
int I18nOpen(const std::string &str, const int flags)
int I18nOpenForReading(const std::string &str)
bool IsStringEncodingValid(const std::string &str)
int I18nOpenForWriting(const std::string &str, const bool append=false)
FILE * I18nFopen(const std::string &str, const std::string &mode)
STL namespace.