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 48 static UFILE* 49 finit_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 129 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 130 u_finit(FILE *f, 131 const char *locale, 132 const char *codepage) 133 { 134 return finit_owner(f, locale, codepage, FALSE); 135 } 136 137 U_CAPI UFILE* U_EXPORT2 138 u_fadopt(FILE *f, 139 const char *locale, 140 const char *codepage) 141 { 142 return finit_owner(f, locale, codepage, TRUE); 143 } 144 145 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 146 u_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 168 U_CAPI UFILE* U_EXPORT2 169 u_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 197 U_CAPI UFILE* U_EXPORT2 198 u_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 230 U_CAPI UBool U_EXPORT2 231 u_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 244 U_CAPI void U_EXPORT2 245 u_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 258 U_CAPI void 259 u_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 273 U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 274 u_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 292 U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 293 u_fgetfile( UFILE *f) 294 { 295 return f->fFile; 296 } 297 298 #if !UCONFIG_NO_FORMATTING 299 300 U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 301 u_fgetlocale( UFILE *file) 302 { 303 return file->str.fBundle.fLocale; 304 } 305 306 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 307 u_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 317 U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 318 u_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 331 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 332 u_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 350 U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */ 351 u_fgetConverter(UFILE *file) 352 { 353 return file->fConverter; 354 } 355 #if !UCONFIG_NO_FORMATTING 356 U_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