tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ufile.cpp (11122B)


      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 U_PLATFORM == U_PF_CYGWIN && defined(__STRICT_ANSI__)
     25 /* GCC on cygwin (not msys2) with -std=c++11 or newer has stopped defining fileno,
     26   unless gcc extensions are enabled (-std=gnu11).
     27   fileno is POSIX, but is not standard ANSI C.
     28   It has always been a GCC extension, which everyone used until recently.
     29   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40278#c7
     30 
     31   For cygwin/mingw, the FILE* pointer isn't opaque, so we can just use a simple macro.
     32   Suggested fix from: https://github.com/gabime/spdlog/issues/1581#issuecomment-650323251
     33 */
     34 #define _fileno(__F) ((__F)->_file)
     35 #define fileno(__F) _fileno(__F)
     36 #endif
     37 
     38 #include "locmap.h"
     39 #include "unicode/ustdio.h"
     40 
     41 #if !UCONFIG_NO_CONVERSION
     42 
     43 #include <stdlib.h>
     44 
     45 #include "ufile.h"
     46 #include "unicode/uloc.h"
     47 #include "unicode/ures.h"
     48 #include "unicode/ucnv.h"
     49 #include "unicode/ustring.h"
     50 #include "unicode/unistr.h"
     51 #include "cstring.h"
     52 #include "cmemory.h"
     53 
     54 #if U_PLATFORM_USES_ONLY_WIN32_API && !defined(fileno)
     55 /* We will just create an alias to Microsoft's implementation,
     56   which is prefixed with _ as they deprecated non-ansi-standard POSIX function names.
     57   https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/posix-fileno?view=msvc-170
     58 */
     59 #define fileno _fileno
     60 #endif
     61 
     62 static UFILE*
     63 finit_owner(FILE         *f,
     64              const char *locale,
     65              const char *codepage,
     66              UBool       takeOwnership
     67              )
     68 {
     69    UErrorCode status = U_ZERO_ERROR;
     70    UFILE     *result;
     71    if(f == nullptr) {
     72        return nullptr;
     73    }
     74    result = static_cast<UFILE*>(uprv_malloc(sizeof(UFILE)));
     75    if(result == nullptr) {
     76        return nullptr;
     77    }
     78 
     79    uprv_memset(result, 0, sizeof(UFILE));
     80    result->fFileno = fileno(f);
     81    result->fFile = f;
     82 
     83    result->str.fBuffer = result->fUCBuffer;
     84    result->str.fPos    = result->fUCBuffer;
     85    result->str.fLimit  = result->fUCBuffer;
     86 
     87 #if !UCONFIG_NO_FORMATTING
     88        /* if locale is 0, use the default */
     89        if (u_locbund_init(&result->str.fBundle, locale) == nullptr) {
     90            /* DO NOT FCLOSE HERE! */
     91            uprv_free(result);
     92            return nullptr;
     93        }
     94 #endif
     95 
     96    /* If the codepage is not "" use the ucnv_open default behavior */
     97    if(codepage == nullptr || *codepage != '\0') {
     98        result->fConverter = ucnv_open(codepage, &status);
     99    }
    100    /* else result->fConverter is already memset'd to nullptr. */
    101 
    102    if(U_SUCCESS(status)) {
    103        result->fOwnFile = takeOwnership;
    104    }
    105    else {
    106 #if !UCONFIG_NO_FORMATTING
    107        u_locbund_close(&result->str.fBundle);
    108 #endif
    109        /* DO NOT fclose here!!!!!! */
    110        uprv_free(result);
    111        result = nullptr;
    112    }
    113 
    114    return result;
    115 }
    116 
    117 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    118 u_finit(FILE          *f,
    119        const char    *locale,
    120        const char    *codepage)
    121 {
    122    return finit_owner(f, locale, codepage, false);
    123 }
    124 
    125 U_CAPI UFILE* U_EXPORT2
    126 u_fadopt(FILE         *f,
    127        const char    *locale,
    128        const char    *codepage)
    129 {
    130    return finit_owner(f, locale, codepage, true);
    131 }
    132 
    133 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    134 u_fopen(const char    *filename,
    135        const char    *perm,
    136        const char    *locale,
    137        const char    *codepage)
    138 {
    139    UFILE     *result;
    140    FILE     *systemFile = fopen(filename, perm);
    141    if (systemFile == nullptr) {
    142        return nullptr;
    143    }
    144 
    145    result = finit_owner(systemFile, locale, codepage, true);
    146 
    147    if (!result) {
    148        /* Something bad happened.
    149           Maybe the converter couldn't be opened. */
    150        fclose(systemFile);
    151    }
    152 
    153    return result; /* not a file leak */
    154 }
    155 
    156 // FILENAME_BUF_MAX represents the largest size that we are willing to use for a
    157 // stack-allocated buffer to contain a file name or path. If PATH_MAX (POSIX) or MAX_PATH
    158 // (Windows) are defined and are smaller than this we will use their defined value;
    159 // otherwise, we will use FILENAME_BUF_MAX for the stack-allocated buffer, and dynamically
    160 // allocate a buffer for any file name or path that is that length or longer.
    161 #define FILENAME_BUF_MAX 296
    162 #if defined PATH_MAX && PATH_MAX < FILENAME_BUF_MAX
    163 #define FILENAME_BUF_CAPACITY PATH_MAX
    164 #elif defined MAX_PATH && MAX_PATH < FILENAME_BUF_MAX
    165 #define FILENAME_BUF_CAPACITY MAX_PATH
    166 #else
    167 #define FILENAME_BUF_CAPACITY FILENAME_BUF_MAX
    168 #endif
    169 
    170 U_CAPI UFILE* U_EXPORT2
    171 u_fopen_u(const char16_t   *filename,
    172        const char    *perm,
    173        const char    *locale,
    174        const char    *codepage)
    175 {
    176    UFILE *result;
    177    char buffer[FILENAME_BUF_CAPACITY];
    178    char *filenameBuffer = buffer;
    179 
    180    icu::UnicodeString filenameString(true, filename, -1); // readonly aliasing, does not allocate memory
    181    // extract with conversion to platform default codepage, return full length (not including 0 termination)
    182    int32_t filenameLength = filenameString.extract(0, filenameString.length(), filenameBuffer, FILENAME_BUF_CAPACITY);
    183    if (filenameLength >= FILENAME_BUF_CAPACITY) { // could not fit (with zero termination) in buffer
    184        filenameBuffer = static_cast<char *>(uprv_malloc(++filenameLength)); // add one for zero termination
    185        if (!filenameBuffer) {
    186            return nullptr;
    187        }
    188        filenameString.extract(0, filenameString.length(), filenameBuffer, filenameLength);
    189    }
    190 
    191    result = u_fopen(filenameBuffer, perm, locale, codepage);
    192 #if U_PLATFORM_USES_ONLY_WIN32_API
    193    /* Try Windows API _wfopen if the above fails. */
    194    if (!result) {
    195        // TODO: test this code path, including wperm.
    196        wchar_t wperm[40] = {};
    197        size_t  retVal;
    198        mbstowcs_s(&retVal, wperm, UPRV_LENGTHOF(wperm), perm, _TRUNCATE);
    199        FILE *systemFile = _wfopen(reinterpret_cast<const wchar_t *>(filename), wperm); // may return nullptr for long filename
    200        if (systemFile) {
    201            result = finit_owner(systemFile, locale, codepage, true);
    202        }
    203        if (!result && systemFile) {
    204            /* Something bad happened.
    205               Maybe the converter couldn't be opened.
    206               Bu do not fclose(systemFile) if systemFile is nullptr. */
    207            fclose(systemFile);
    208        }
    209    }
    210 #endif
    211    if (filenameBuffer != buffer) {
    212        uprv_free(filenameBuffer);
    213    }
    214    return result; /* not a file leak */
    215 }
    216 
    217 
    218 U_CAPI UFILE* U_EXPORT2
    219 u_fstropen(char16_t *stringBuf,
    220           int32_t      capacity,
    221           const char  *locale)
    222 {
    223    UFILE *result;
    224 
    225    if (capacity < 0) {
    226        return nullptr;
    227    }
    228 
    229    result = (UFILE*) uprv_malloc(sizeof(UFILE));
    230    /* Null pointer test */
    231    if (result == nullptr) {
    232        return nullptr; /* Just get out. */
    233    }
    234    uprv_memset(result, 0, sizeof(UFILE));
    235    result->str.fBuffer = stringBuf;
    236    result->str.fPos    = stringBuf;
    237    result->str.fLimit  = stringBuf+capacity;
    238 
    239 #if !UCONFIG_NO_FORMATTING
    240    /* if locale is 0, use the default */
    241    if (u_locbund_init(&result->str.fBundle, locale) == nullptr) {
    242        /* DO NOT FCLOSE HERE! */
    243        uprv_free(result);
    244        return nullptr;
    245    }
    246 #endif
    247 
    248    return result;
    249 }
    250 
    251 U_CAPI UBool U_EXPORT2
    252 u_feof(UFILE  *f)
    253 {
    254    UBool endOfBuffer;
    255    if (f == nullptr) {
    256        return true;
    257    }
    258    endOfBuffer = f->str.fPos >= f->str.fLimit;
    259    if (f->fFile != nullptr) {
    260        return endOfBuffer && feof(f->fFile);
    261    }
    262    return endOfBuffer;
    263 }
    264 
    265 U_CAPI void U_EXPORT2
    266 u_fflush(UFILE *file)
    267 {
    268    ufile_flush_translit(file);
    269    ufile_flush_io(file);
    270    if (file->fFile) {
    271        fflush(file->fFile);
    272    }
    273    else if (file->str.fPos < file->str.fLimit) {
    274        *(file->str.fPos++) = 0;
    275    }
    276    /* TODO: flush input */
    277 }
    278 
    279 U_CAPI void
    280 u_frewind(UFILE *file)
    281 {
    282    u_fflush(file);
    283    ucnv_reset(file->fConverter);
    284    if (file->fFile) {
    285        rewind(file->fFile);
    286        file->str.fLimit = file->fUCBuffer;
    287        file->str.fPos   = file->fUCBuffer;
    288    }
    289    else {
    290        file->str.fPos = file->str.fBuffer;
    291    }
    292 }
    293 
    294 U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    295 u_fclose(UFILE *file)
    296 {
    297    if (file) {
    298        u_fflush(file);
    299        ufile_close_translit(file);
    300 
    301        if(file->fOwnFile)
    302            fclose(file->fFile);
    303 
    304 #if !UCONFIG_NO_FORMATTING
    305        u_locbund_close(&file->str.fBundle);
    306 #endif
    307 
    308        ucnv_close(file->fConverter);
    309        uprv_free(file);
    310    }
    311 }
    312 
    313 U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    314 u_fgetfile(    UFILE         *f)
    315 {
    316    return f->fFile;
    317 }
    318 
    319 #if !UCONFIG_NO_FORMATTING
    320 
    321 U_CAPI const char*  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    322 u_fgetlocale(    UFILE        *file)
    323 {
    324    return file->str.fBundle.fLocale;
    325 }
    326 
    327 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    328 u_fsetlocale(UFILE      *file,
    329             const char *locale)
    330 {
    331    u_locbund_close(&file->str.fBundle);
    332 
    333    return u_locbund_init(&file->str.fBundle, locale) == nullptr ? -1 : 0;
    334 }
    335 
    336 #endif
    337 
    338 U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    339 u_fgetcodepage(UFILE        *file)
    340 {
    341    UErrorCode     status = U_ZERO_ERROR;
    342    const char     *codepage = nullptr;
    343 
    344    if (file->fConverter) {
    345        codepage = ucnv_getName(file->fConverter, &status);
    346        if(U_FAILURE(status))
    347            return nullptr;
    348    }
    349    return codepage;
    350 }
    351 
    352 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    353 u_fsetcodepage(    const char    *codepage,
    354               UFILE        *file)
    355 {
    356    UErrorCode status = U_ZERO_ERROR;
    357    int32_t retVal = -1;
    358 
    359    /* We use the normal default codepage for this system, and not the one for the locale. */
    360    if ((file->str.fPos == file->str.fBuffer) && (file->str.fLimit == file->str.fBuffer)) {
    361        ucnv_close(file->fConverter);
    362        file->fConverter = ucnv_open(codepage, &status);
    363        if(U_SUCCESS(status)) {
    364            retVal = 0;
    365        }
    366    }
    367    return retVal;
    368 }
    369 
    370 
    371 U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    372 u_fgetConverter(UFILE *file)
    373 {
    374    return file->fConverter;
    375 }
    376 #if !UCONFIG_NO_FORMATTING
    377 U_CAPI const UNumberFormat* U_EXPORT2 u_fgetNumberFormat(UFILE *file)
    378 {
    379    return u_locbund_getNumberFormat(&file->str.fBundle, UNUM_DECIMAL);
    380 }
    381 #endif
    382 
    383 #endif