• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 *
6 *   Copyright (C) 1998-2015, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 ******************************************************************************
10 *
11 * File ufile.cpp
12 *
13 * Modification History:
14 *
15 *   Date        Name        Description
16 *   11/19/98    stephen     Creation.
17 *   03/12/99    stephen     Modified for new C API.
18 *   06/16/99    stephen     Changed T_LocaleBundle to u_locbund
19 *   07/19/99    stephen     Fixed to use ucnv's default codepage.
20 ******************************************************************************
21 */
22 
23 #include "unicode/platform.h"
24 #if defined(__GNUC__) && !defined(__clang__) && defined(__STRICT_ANSI__)
25 // g++, fileno isn't defined                  if     __STRICT_ANSI__ is defined.
26 // clang fails to compile the <string> header unless __STRICT_ANSI__ is defined.
27 // __GNUC__ is set by both gcc and clang.
28 #undef __STRICT_ANSI__
29 #endif
30 
31 #include "locmap.h"
32 #include "unicode/ustdio.h"
33 
34 #if !UCONFIG_NO_CONVERSION
35 
36 #include <stdlib.h>
37 
38 #include "ufile.h"
39 #include "unicode/uloc.h"
40 #include "unicode/ures.h"
41 #include "unicode/ucnv.h"
42 #include "unicode/ustring.h"
43 #include "unicode/unistr.h"
44 #include "cstring.h"
45 #include "cmemory.h"
46 
47 #if U_PLATFORM_USES_ONLY_WIN32_API && !defined(fileno)
48 /* Windows likes to rename Unix-like functions */
49 #define fileno _fileno
50 #endif
51 
52 static UFILE*
finit_owner(FILE * f,const char * locale,const char * codepage,UBool takeOwnership)53 finit_owner(FILE         *f,
54               const char *locale,
55               const char *codepage,
56               UBool       takeOwnership
57               )
58 {
59     UErrorCode status = U_ZERO_ERROR;
60     UFILE     *result;
61     if(f == NULL) {
62         return 0;
63     }
64     result = (UFILE*) uprv_malloc(sizeof(UFILE));
65     if(result == NULL) {
66         return 0;
67     }
68 
69     uprv_memset(result, 0, sizeof(UFILE));
70     result->fFileno = fileno(f);
71     result->fFile = f;
72 
73     result->str.fBuffer = result->fUCBuffer;
74     result->str.fPos    = result->fUCBuffer;
75     result->str.fLimit  = result->fUCBuffer;
76 
77 #if !UCONFIG_NO_FORMATTING
78         /* if locale is 0, use the default */
79         if(u_locbund_init(&result->str.fBundle, locale) == 0) {
80             /* DO NOT FCLOSE HERE! */
81             uprv_free(result);
82             return 0;
83         }
84 #endif
85 
86     /* If the codepage is not "" use the ucnv_open default behavior */
87     if(codepage == NULL || *codepage != '\0') {
88         result->fConverter = ucnv_open(codepage, &status);
89     }
90     /* else result->fConverter is already memset'd to NULL. */
91 
92     if(U_SUCCESS(status)) {
93         result->fOwnFile = takeOwnership;
94     }
95     else {
96 #if !UCONFIG_NO_FORMATTING
97         u_locbund_close(&result->str.fBundle);
98 #endif
99         /* DO NOT fclose here!!!!!! */
100         uprv_free(result);
101         result = NULL;
102     }
103 
104     return result;
105 }
106 
107 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_finit(FILE * f,const char * locale,const char * codepage)108 u_finit(FILE          *f,
109         const char    *locale,
110         const char    *codepage)
111 {
112     return finit_owner(f, locale, codepage, FALSE);
113 }
114 
115 U_CAPI UFILE* U_EXPORT2
u_fadopt(FILE * f,const char * locale,const char * codepage)116 u_fadopt(FILE         *f,
117         const char    *locale,
118         const char    *codepage)
119 {
120     return finit_owner(f, locale, codepage, TRUE);
121 }
122 
123 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fopen(const char * filename,const char * perm,const char * locale,const char * codepage)124 u_fopen(const char    *filename,
125         const char    *perm,
126         const char    *locale,
127         const char    *codepage)
128 {
129     UFILE     *result;
130     FILE     *systemFile = fopen(filename, perm);
131     if(systemFile == 0) {
132         return 0;
133     }
134 
135     result = finit_owner(systemFile, locale, codepage, TRUE);
136 
137     if (!result) {
138         /* Something bad happened.
139            Maybe the converter couldn't be opened. */
140         fclose(systemFile);
141     }
142 
143     return result; /* not a file leak */
144 }
145 
146 // FILENAME_BUF_MAX represents the largest size that we are willing to use for a
147 // stack-allocated buffer to contain a file name or path. If PATH_MAX (POSIX) or MAX_PATH
148 // (Windows) are defined and are smaller than this we will use their defined value;
149 // otherwise, we will use FILENAME_BUF_MAX for the stack-allocated buffer, and dynamically
150 // allocate a buffer for any file name or path that is that length or longer.
151 #define FILENAME_BUF_MAX 296
152 #if defined PATH_MAX && PATH_MAX < FILENAME_BUF_MAX
153 #define FILENAME_BUF_CAPACITY PATH_MAX
154 #elif defined MAX_PATH && MAX_PATH < FILENAME_BUF_MAX
155 #define FILENAME_BUF_CAPACITY MAX_PATH
156 #else
157 #define FILENAME_BUF_CAPACITY FILENAME_BUF_MAX
158 #endif
159 
160 U_CAPI UFILE* U_EXPORT2
u_fopen_u(const UChar * filename,const char * perm,const char * locale,const char * codepage)161 u_fopen_u(const UChar   *filename,
162         const char    *perm,
163         const char    *locale,
164         const char    *codepage)
165 {
166     UFILE *result;
167     char buffer[FILENAME_BUF_CAPACITY];
168     char *filenameBuffer = buffer;
169 
170     icu::UnicodeString filenameString(true, filename, -1); // readonly aliasing, does not allocate memory
171     // extract with conversion to platform default codepage, return full length (not including 0 termination)
172     int32_t filenameLength = filenameString.extract(0, filenameString.length(), filenameBuffer, FILENAME_BUF_CAPACITY);
173     if (filenameLength >= FILENAME_BUF_CAPACITY) { // could not fit (with zero termination) in buffer
174         filenameBuffer = static_cast<char *>(uprv_malloc(++filenameLength)); // add one for zero termination
175         if (!filenameBuffer) {
176             return nullptr;
177         }
178         filenameString.extract(0, filenameString.length(), filenameBuffer, filenameLength);
179     }
180 
181     result = u_fopen(filenameBuffer, perm, locale, codepage);
182 #if U_PLATFORM_USES_ONLY_WIN32_API
183     /* Try Windows API _wfopen if the above fails. */
184     if (!result) {
185         // TODO: test this code path, including wperm.
186         wchar_t wperm[40] = {};
187         size_t  retVal;
188         mbstowcs_s(&retVal, wperm, UPRV_LENGTHOF(wperm), perm, _TRUNCATE);
189         FILE *systemFile = _wfopen(reinterpret_cast<const wchar_t *>(filename), wperm); // may return NULL for long filename
190         if (systemFile) {
191             result = finit_owner(systemFile, locale, codepage, TRUE);
192         }
193         if (!result && systemFile) {
194             /* Something bad happened.
195                Maybe the converter couldn't be opened.
196                Bu do not fclose(systemFile) if systemFile is NULL. */
197             fclose(systemFile);
198         }
199     }
200 #endif
201     if (filenameBuffer != buffer) {
202         uprv_free(filenameBuffer);
203     }
204     return result; /* not a file leak */
205 }
206 
207 
208 U_CAPI UFILE* U_EXPORT2
u_fstropen(UChar * stringBuf,int32_t capacity,const char * locale)209 u_fstropen(UChar *stringBuf,
210            int32_t      capacity,
211            const char  *locale)
212 {
213     UFILE *result;
214 
215     if (capacity < 0) {
216         return NULL;
217     }
218 
219     result = (UFILE*) uprv_malloc(sizeof(UFILE));
220     /* Null pointer test */
221     if (result == NULL) {
222         return NULL; /* Just get out. */
223     }
224     uprv_memset(result, 0, sizeof(UFILE));
225     result->str.fBuffer = stringBuf;
226     result->str.fPos    = stringBuf;
227     result->str.fLimit  = stringBuf+capacity;
228 
229 #if !UCONFIG_NO_FORMATTING
230     /* if locale is 0, use the default */
231     if(u_locbund_init(&result->str.fBundle, locale) == 0) {
232         /* DO NOT FCLOSE HERE! */
233         uprv_free(result);
234         return 0;
235     }
236 #endif
237 
238     return result;
239 }
240 
241 U_CAPI UBool U_EXPORT2
u_feof(UFILE * f)242 u_feof(UFILE  *f)
243 {
244     UBool endOfBuffer;
245     if (f == NULL) {
246         return TRUE;
247     }
248     endOfBuffer = (UBool)(f->str.fPos >= f->str.fLimit);
249     if (f->fFile != NULL) {
250         return endOfBuffer && feof(f->fFile);
251     }
252     return endOfBuffer;
253 }
254 
255 U_CAPI void U_EXPORT2
u_fflush(UFILE * file)256 u_fflush(UFILE *file)
257 {
258     ufile_flush_translit(file);
259     ufile_flush_io(file);
260     if (file->fFile) {
261         fflush(file->fFile);
262     }
263     else if (file->str.fPos < file->str.fLimit) {
264         *(file->str.fPos++) = 0;
265     }
266     /* TODO: flush input */
267 }
268 
269 U_CAPI void
u_frewind(UFILE * file)270 u_frewind(UFILE *file)
271 {
272     u_fflush(file);
273     ucnv_reset(file->fConverter);
274     if (file->fFile) {
275         rewind(file->fFile);
276         file->str.fLimit = file->fUCBuffer;
277         file->str.fPos   = file->fUCBuffer;
278     }
279     else {
280         file->str.fPos = file->str.fBuffer;
281     }
282 }
283 
284 U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fclose(UFILE * file)285 u_fclose(UFILE *file)
286 {
287     if (file) {
288         u_fflush(file);
289         ufile_close_translit(file);
290 
291         if(file->fOwnFile)
292             fclose(file->fFile);
293 
294 #if !UCONFIG_NO_FORMATTING
295         u_locbund_close(&file->str.fBundle);
296 #endif
297 
298         ucnv_close(file->fConverter);
299         uprv_free(file);
300     }
301 }
302 
303 U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fgetfile(UFILE * f)304 u_fgetfile(    UFILE         *f)
305 {
306     return f->fFile;
307 }
308 
309 #if !UCONFIG_NO_FORMATTING
310 
311 U_CAPI const char*  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fgetlocale(UFILE * file)312 u_fgetlocale(    UFILE        *file)
313 {
314     return file->str.fBundle.fLocale;
315 }
316 
317 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fsetlocale(UFILE * file,const char * locale)318 u_fsetlocale(UFILE      *file,
319              const char *locale)
320 {
321     u_locbund_close(&file->str.fBundle);
322 
323     return u_locbund_init(&file->str.fBundle, locale) == 0 ? -1 : 0;
324 }
325 
326 #endif
327 
328 U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fgetcodepage(UFILE * file)329 u_fgetcodepage(UFILE        *file)
330 {
331     UErrorCode     status = U_ZERO_ERROR;
332     const char     *codepage = NULL;
333 
334     if (file->fConverter) {
335         codepage = ucnv_getName(file->fConverter, &status);
336         if(U_FAILURE(status))
337             return 0;
338     }
339     return codepage;
340 }
341 
342 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fsetcodepage(const char * codepage,UFILE * file)343 u_fsetcodepage(    const char    *codepage,
344                UFILE        *file)
345 {
346     UErrorCode status = U_ZERO_ERROR;
347     int32_t retVal = -1;
348 
349     /* We use the normal default codepage for this system, and not the one for the locale. */
350     if ((file->str.fPos == file->str.fBuffer) && (file->str.fLimit == file->str.fBuffer)) {
351         ucnv_close(file->fConverter);
352         file->fConverter = ucnv_open(codepage, &status);
353         if(U_SUCCESS(status)) {
354             retVal = 0;
355         }
356     }
357     return retVal;
358 }
359 
360 
361 U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_fgetConverter(UFILE * file)362 u_fgetConverter(UFILE *file)
363 {
364     return file->fConverter;
365 }
366 #if !UCONFIG_NO_FORMATTING
u_fgetNumberFormat(UFILE * file)367 U_CAPI const UNumberFormat* U_EXPORT2 u_fgetNumberFormat(UFILE *file)
368 {
369     return u_locbund_getNumberFormat(&file->str.fBundle, UNUM_DECIMAL);
370 }
371 #endif
372 
373 #endif
374