1// Copyright (C) 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.c 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/* 24 * fileno is not declared when building with GCC in strict mode. 25 */ 26#if defined(__GNUC__) && defined(__STRICT_ANSI__) 27#undef __STRICT_ANSI__ 28#endif 29 30#include "locmap.h" 31#include "unicode/ustdio.h" 32 33#if !UCONFIG_NO_CONVERSION 34 35#include "ufile.h" 36#include "unicode/uloc.h" 37#include "unicode/ures.h" 38#include "unicode/ucnv.h" 39#include "unicode/ustring.h" 40#include "cstring.h" 41#include "cmemory.h" 42 43#if U_PLATFORM_USES_ONLY_WIN32_API && !defined(fileno) 44/* Windows likes to rename Unix-like functions */ 45#define fileno _fileno 46#endif 47 48static UFILE* 49finit_owner(FILE *f, 50 const char *locale, 51 const char *codepage, 52 UBool takeOwnership 53 ) 54{ 55 UErrorCode status = U_ZERO_ERROR; 56 UFILE *result; 57 if(f == NULL) { 58 return 0; 59 } 60 result = (UFILE*) uprv_malloc(sizeof(UFILE)); 61 if(result == NULL) { 62 return 0; 63 } 64 65 uprv_memset(result, 0, sizeof(UFILE)); 66 result->fFileno = fileno(f); 67 68#if U_PLATFORM_USES_ONLY_WIN32_API && _MSC_VER < 1900 69 /* 70 * Below is a very old workaround (ICU ticket:231). 71 * 72 * Previously, 'FILE*' from inside and outside ICU's DLL 73 * were different, because they pointed into local copies 74 * of the io block. At least by VS 2015 the implementation 75 * is something like: 76 * stdio = _acrt_iob_func(0) 77 * .. which is a function call, so should return the same pointer 78 * regardless of call site. 79 * As of _MSC_VER 1900 this patch is retired, at 16 years old. 80 */ 81 if (0 <= result->fFileno && result->fFileno <= 2) { 82 /* stdin, stdout and stderr need to be special cased for Windows 98 */ 83#if _MSC_VER >= 1400 84 result->fFile = &__iob_func()[_fileno(f)]; 85#else 86 result->fFile = &_iob[_fileno(f)]; 87#endif 88 } 89 else 90#endif 91 { 92 result->fFile = f; 93 } 94 95 result->str.fBuffer = result->fUCBuffer; 96 result->str.fPos = result->fUCBuffer; 97 result->str.fLimit = result->fUCBuffer; 98 99#if !UCONFIG_NO_FORMATTING 100 /* if locale is 0, use the default */ 101 if(u_locbund_init(&result->str.fBundle, locale) == 0) { 102 /* DO NOT FCLOSE HERE! */ 103 uprv_free(result); 104 return 0; 105 } 106#endif 107 108 /* If the codepage is not "" use the ucnv_open default behavior */ 109 if(codepage == NULL || *codepage != '\0') { 110 result->fConverter = ucnv_open(codepage, &status); 111 } 112 /* else result->fConverter is already memset'd to NULL. */ 113 114 if(U_SUCCESS(status)) { 115 result->fOwnFile = takeOwnership; 116 } 117 else { 118#if !UCONFIG_NO_FORMATTING 119 u_locbund_close(&result->str.fBundle); 120#endif 121 /* DO NOT fclose here!!!!!! */ 122 uprv_free(result); 123 result = NULL; 124 } 125 126 return result; 127} 128 129U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 130u_finit(FILE *f, 131 const char *locale, 132 const char *codepage) 133{ 134 return finit_owner(f, locale, codepage, FALSE); 135} 136 137U_CAPI UFILE* U_EXPORT2 138u_fadopt(FILE *f, 139 const char *locale, 140 const char *codepage) 141{ 142 return finit_owner(f, locale, codepage, TRUE); 143} 144 145U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 146u_fopen(const char *filename, 147 const char *perm, 148 const char *locale, 149 const char *codepage) 150{ 151 UFILE *result; 152 FILE *systemFile = fopen(filename, perm); 153 if(systemFile == 0) { 154 return 0; 155 } 156 157 result = finit_owner(systemFile, locale, codepage, TRUE); 158 159 if (!result) { 160 /* Something bad happened. 161 Maybe the converter couldn't be opened. */ 162 fclose(systemFile); 163 } 164 165 return result; /* not a file leak */ 166} 167 168U_CAPI UFILE* U_EXPORT2 169u_fopen_u(const UChar *filename, 170 const char *perm, 171 const char *locale, 172 const char *codepage) 173{ 174 UFILE *result; 175 char buffer[256]; 176 177 u_austrcpy(buffer, filename); 178 179 result = u_fopen(buffer, perm, locale, codepage); 180#if U_PLATFORM_USES_ONLY_WIN32_API 181 /* Try Windows API _wfopen if the above fails. */ 182 if (!result) { 183 FILE *systemFile = _wfopen(filename, (UChar*)perm); 184 if (systemFile) { 185 result = finit_owner(systemFile, locale, codepage, TRUE); 186 } 187 if (!result) { 188 /* Something bad happened. 189 Maybe the converter couldn't be opened. */ 190 fclose(systemFile); 191 } 192 } 193#endif 194 return result; /* not a file leak */ 195} 196 197U_CAPI UFILE* U_EXPORT2 198u_fstropen(UChar *stringBuf, 199 int32_t capacity, 200 const char *locale) 201{ 202 UFILE *result; 203 204 if (capacity < 0) { 205 return NULL; 206 } 207 208 result = (UFILE*) uprv_malloc(sizeof(UFILE)); 209 /* Null pointer test */ 210 if (result == NULL) { 211 return NULL; /* Just get out. */ 212 } 213 uprv_memset(result, 0, sizeof(UFILE)); 214 result->str.fBuffer = stringBuf; 215 result->str.fPos = stringBuf; 216 result->str.fLimit = stringBuf+capacity; 217 218#if !UCONFIG_NO_FORMATTING 219 /* if locale is 0, use the default */ 220 if(u_locbund_init(&result->str.fBundle, locale) == 0) { 221 /* DO NOT FCLOSE HERE! */ 222 uprv_free(result); 223 return 0; 224 } 225#endif 226 227 return result; 228} 229 230U_CAPI UBool U_EXPORT2 231u_feof(UFILE *f) 232{ 233 UBool endOfBuffer; 234 if (f == NULL) { 235 return TRUE; 236 } 237 endOfBuffer = (UBool)(f->str.fPos >= f->str.fLimit); 238 if (f->fFile != NULL) { 239 return endOfBuffer && feof(f->fFile); 240 } 241 return endOfBuffer; 242} 243 244U_CAPI void U_EXPORT2 245u_fflush(UFILE *file) 246{ 247 ufile_flush_translit(file); 248 ufile_flush_io(file); 249 if (file->fFile) { 250 fflush(file->fFile); 251 } 252 else if (file->str.fPos < file->str.fLimit) { 253 *(file->str.fPos++) = 0; 254 } 255 /* TODO: flush input */ 256} 257 258U_CAPI void 259u_frewind(UFILE *file) 260{ 261 u_fflush(file); 262 ucnv_reset(file->fConverter); 263 if (file->fFile) { 264 rewind(file->fFile); 265 file->str.fLimit = file->fUCBuffer; 266 file->str.fPos = file->fUCBuffer; 267 } 268 else { 269 file->str.fPos = file->str.fBuffer; 270 } 271} 272 273U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 274u_fclose(UFILE *file) 275{ 276 if (file) { 277 u_fflush(file); 278 ufile_close_translit(file); 279 280 if(file->fOwnFile) 281 fclose(file->fFile); 282 283#if !UCONFIG_NO_FORMATTING 284 u_locbund_close(&file->str.fBundle); 285#endif 286 287 ucnv_close(file->fConverter); 288 uprv_free(file); 289 } 290} 291 292U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 293u_fgetfile( UFILE *f) 294{ 295 return f->fFile; 296} 297 298#if !UCONFIG_NO_FORMATTING 299 300U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 301u_fgetlocale( UFILE *file) 302{ 303 return file->str.fBundle.fLocale; 304} 305 306U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 307u_fsetlocale(UFILE *file, 308 const char *locale) 309{ 310 u_locbund_close(&file->str.fBundle); 311 312 return u_locbund_init(&file->str.fBundle, locale) == 0 ? -1 : 0; 313} 314 315#endif 316 317U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 318u_fgetcodepage(UFILE *file) 319{ 320 UErrorCode status = U_ZERO_ERROR; 321 const char *codepage = NULL; 322 323 if (file->fConverter) { 324 codepage = ucnv_getName(file->fConverter, &status); 325 if(U_FAILURE(status)) 326 return 0; 327 } 328 return codepage; 329} 330 331U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 332u_fsetcodepage( const char *codepage, 333 UFILE *file) 334{ 335 UErrorCode status = U_ZERO_ERROR; 336 int32_t retVal = -1; 337 338 /* We use the normal default codepage for this system, and not the one for the locale. */ 339 if ((file->str.fPos == file->str.fBuffer) && (file->str.fLimit == file->str.fBuffer)) { 340 ucnv_close(file->fConverter); 341 file->fConverter = ucnv_open(codepage, &status); 342 if(U_SUCCESS(status)) { 343 retVal = 0; 344 } 345 } 346 return retVal; 347} 348 349 350U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 351u_fgetConverter(UFILE *file) 352{ 353 return file->fConverter; 354} 355#if !UCONFIG_NO_FORMATTING 356U_CAPI const UNumberFormat* U_EXPORT2 u_fgetNumberFormat(UFILE *file) 357{ 358 return u_locbund_getNumberFormat(&file->str.fBundle, UNUM_DECIMAL); 359} 360#endif 361 362#endif 363