blob: 607601935cf4c500fb86e98675a24ca6da592f8f [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003/*
4******************************************************************************
5*
Jungshik Shin70f82502016-01-29 00:32:36 -08006* Copyright (C) 1998-2015, International Business Machines
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00007* Corporation and others. All Rights Reserved.
8*
9******************************************************************************
10*
Jungshik Shin87232d82017-05-13 21:10:13 -070011* File ufile.cpp
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000012*
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
Jungshik Shin87232d82017-05-13 21:10:13 -070023#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.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000028#undef __STRICT_ANSI__
29#endif
30
31#include "locmap.h"
32#include "unicode/ustdio.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080033
34#if !UCONFIG_NO_CONVERSION
35
Jungshik Shin87232d82017-05-13 21:10:13 -070036#include <stdlib.h>
37
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000038#include "ufile.h"
39#include "unicode/uloc.h"
40#include "unicode/ures.h"
41#include "unicode/ucnv.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080042#include "unicode/ustring.h"
Frank Tangf90543d2020-10-30 19:02:04 -070043#include "unicode/unistr.h"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000044#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
52static UFILE*
53finit_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);
Jungshik Shin87232d82017-05-13 21:10:13 -070071 result->fFile = f;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000072
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
107U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
108u_finit(FILE *f,
109 const char *locale,
110 const char *codepage)
111{
112 return finit_owner(f, locale, codepage, FALSE);
113}
114
115U_CAPI UFILE* U_EXPORT2
116u_fadopt(FILE *f,
117 const char *locale,
118 const char *codepage)
119{
120 return finit_owner(f, locale, codepage, TRUE);
121}
122
123U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
124u_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
Frank Tangf90543d2020-10-30 19:02:04 -0700146// 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
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000160U_CAPI UFILE* U_EXPORT2
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800161u_fopen_u(const UChar *filename,
162 const char *perm,
163 const char *locale,
164 const char *codepage)
165{
Frank Tangf90543d2020-10-30 19:02:04 -0700166 UFILE *result;
167 char buffer[FILENAME_BUF_CAPACITY];
168 char *filenameBuffer = buffer;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800169
Frank Tangf90543d2020-10-30 19:02:04 -0700170 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 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800180
Frank Tangf90543d2020-10-30 19:02:04 -0700181 result = u_fopen(filenameBuffer, perm, locale, codepage);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800182#if U_PLATFORM_USES_ONLY_WIN32_API
183 /* Try Windows API _wfopen if the above fails. */
184 if (!result) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700185 // TODO: test this code path, including wperm.
186 wchar_t wperm[40] = {};
187 size_t retVal;
Jungshik Shinb3189662017-11-07 11:18:34 -0800188 mbstowcs_s(&retVal, wperm, UPRV_LENGTHOF(wperm), perm, _TRUNCATE);
Frank Tangf90543d2020-10-30 19:02:04 -0700189 FILE *systemFile = _wfopen(reinterpret_cast<const wchar_t *>(filename), wperm); // may return NULL for long filename
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800190 if (systemFile) {
191 result = finit_owner(systemFile, locale, codepage, TRUE);
192 }
Frank Tangf90543d2020-10-30 19:02:04 -0700193 if (!result && systemFile) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800194 /* Something bad happened.
Frank Tangf90543d2020-10-30 19:02:04 -0700195 Maybe the converter couldn't be opened.
196 Bu do not fclose(systemFile) if systemFile is NULL. */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800197 fclose(systemFile);
198 }
199 }
200#endif
Frank Tangf90543d2020-10-30 19:02:04 -0700201 if (filenameBuffer != buffer) {
202 uprv_free(filenameBuffer);
203 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800204 return result; /* not a file leak */
205}
206
Frank Tangf90543d2020-10-30 19:02:04 -0700207
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800208U_CAPI UFILE* U_EXPORT2
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000209u_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) {
Jungshik Shin87232d82017-05-13 21:10:13 -0700222 return NULL; /* Just get out. */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000223 }
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
241U_CAPI UBool U_EXPORT2
242u_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
255U_CAPI void U_EXPORT2
256u_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
269U_CAPI void
270u_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
284U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
285u_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
303U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
304u_fgetfile( UFILE *f)
305{
306 return f->fFile;
307}
308
309#if !UCONFIG_NO_FORMATTING
310
311U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
312u_fgetlocale( UFILE *file)
313{
314 return file->str.fBundle.fLocale;
315}
316
317U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
318u_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
328U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
329u_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
342U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
343u_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
361U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
362u_fgetConverter(UFILE *file)
363{
364 return file->fConverter;
365}
366#if !UCONFIG_NO_FORMATTING
367U_CAPI const UNumberFormat* U_EXPORT2 u_fgetNumberFormat(UFILE *file)
368{
369 return u_locbund_getNumberFormat(&file->str.fBundle, UNUM_DECIMAL);
370}
371#endif
372
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800373#endif