tor-browser

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

ustdio.cpp (20057B)


      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-2016, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 ******************************************************************************
     10 *
     11 * File ustdio.c
     12 *
     13 * Modification History:
     14 *
     15 *   Date        Name        Description
     16 *   11/18/98    stephen     Creation.
     17 *   03/12/99    stephen     Modified for new C API.
     18 *   07/19/99    stephen     Fixed read() and gets()
     19 ******************************************************************************
     20 */
     21 
     22 #include "unicode/ustdio.h"
     23 
     24 #if !UCONFIG_NO_CONVERSION
     25 
     26 #include "unicode/putil.h"
     27 #include "cmemory.h"
     28 #include "cstring.h"
     29 #include "ufile.h"
     30 #include "ufmt_cmn.h"
     31 #include "unicode/ucnv.h"
     32 #include "unicode/ustring.h"
     33 
     34 #include <string.h>
     35 
     36 #define DELIM_LF 0x000A
     37 #define DELIM_VT 0x000B
     38 #define DELIM_FF 0x000C
     39 #define DELIM_CR 0x000D
     40 #define DELIM_NEL 0x0085
     41 #define DELIM_LS 0x2028
     42 #define DELIM_PS 0x2029
     43 
     44 /* TODO: is this correct for all codepages? Should we just use \n and let the converter handle it? */
     45 #if U_PLATFORM_USES_ONLY_WIN32_API
     46 static const char16_t DELIMITERS [] = { DELIM_CR, DELIM_LF, 0x0000 };
     47 static const uint32_t DELIMITERS_LEN = 2;
     48 /* TODO: Default newline writing should be detected based upon the converter being used. */
     49 #else
     50 static const char16_t DELIMITERS [] = { DELIM_LF, 0x0000 };
     51 static const uint32_t DELIMITERS_LEN = 1;
     52 #endif
     53 
     54 #define IS_FIRST_STRING_DELIMITER(c1) \
     55 (UBool)((DELIM_LF <= (c1) && (c1) <= DELIM_CR) \
     56        || (c1) == DELIM_NEL \
     57        || (c1) == DELIM_LS \
     58        || (c1) == DELIM_PS)
     59 #define CAN_HAVE_COMBINED_STRING_DELIMITER(c1) (UBool)((c1) == DELIM_CR)
     60 #define IS_COMBINED_STRING_DELIMITER(c1, c2) \
     61 (UBool)((c1) == DELIM_CR && (c2) == DELIM_LF)
     62 
     63 
     64 #if !UCONFIG_NO_TRANSLITERATION
     65 
     66 U_CAPI UTransliterator* U_EXPORT2
     67 u_fsettransliterator(UFILE *file, UFileDirection direction,
     68                     UTransliterator *adopt, UErrorCode *status)
     69 {
     70    UTransliterator *old = nullptr;
     71 
     72    if(U_FAILURE(*status))
     73    {
     74        return adopt;
     75    }
     76 
     77    if(!file)
     78    {
     79        *status = U_ILLEGAL_ARGUMENT_ERROR;
     80        return adopt;
     81    }
     82 
     83    if(direction & U_READ)
     84    {
     85        /** TODO: implement */
     86        *status = U_UNSUPPORTED_ERROR;
     87        return adopt;
     88    }
     89 
     90    if(adopt == nullptr) /* they are clearing it */
     91    {
     92        if(file->fTranslit != nullptr)
     93        {
     94            /* TODO: Check side */
     95            old = file->fTranslit->translit;
     96            uprv_free(file->fTranslit->buffer);
     97            file->fTranslit->buffer=nullptr;
     98            uprv_free(file->fTranslit);
     99            file->fTranslit=nullptr;
    100        }
    101    }
    102    else
    103    {
    104        if(file->fTranslit == nullptr)
    105        {
    106            file->fTranslit = (UFILETranslitBuffer*) uprv_malloc(sizeof(UFILETranslitBuffer));
    107            if(!file->fTranslit)
    108            {
    109                *status = U_MEMORY_ALLOCATION_ERROR;
    110                return adopt;
    111            }
    112            file->fTranslit->capacity = 0;
    113            file->fTranslit->length = 0;
    114            file->fTranslit->pos = 0;
    115            file->fTranslit->buffer = nullptr;
    116        }
    117        else
    118        {
    119            old = file->fTranslit->translit;
    120            ufile_flush_translit(file);
    121        }
    122 
    123        file->fTranslit->translit = adopt;
    124    }
    125 
    126    return old;
    127 }
    128 
    129 static const char16_t * u_file_translit(UFILE *f, const char16_t *src, int32_t *count, UBool flush)
    130 {
    131    int32_t newlen;
    132    int32_t junkCount = 0;
    133    int32_t textLength;
    134    int32_t textLimit;
    135    UTransPosition pos;
    136    UErrorCode status = U_ZERO_ERROR;
    137 
    138    if(count == nullptr)
    139    {
    140        count = &junkCount;
    141    }
    142 
    143    if ((!f)||(!f->fTranslit)||(!f->fTranslit->translit))
    144    {
    145        /* fast path */
    146        return src;
    147    }
    148 
    149    /* First: slide over everything */
    150    if(f->fTranslit->length > f->fTranslit->pos)
    151    {
    152        memmove(f->fTranslit->buffer, f->fTranslit->buffer + f->fTranslit->pos,
    153            (f->fTranslit->length - f->fTranslit->pos)*sizeof(char16_t));
    154    }
    155    f->fTranslit->length -= f->fTranslit->pos; /* always */
    156    f->fTranslit->pos = 0;
    157 
    158    /* Calculate new buffer size needed */
    159    newlen = (*count + f->fTranslit->length) * 4;
    160 
    161    if(newlen > f->fTranslit->capacity)
    162    {
    163        if(f->fTranslit->buffer == nullptr)
    164        {
    165            f->fTranslit->buffer = static_cast<char16_t*>(uprv_malloc(newlen * sizeof(char16_t)));
    166        }
    167        else
    168        {
    169            f->fTranslit->buffer = static_cast<char16_t*>(uprv_realloc(f->fTranslit->buffer, newlen * sizeof(char16_t)));
    170        }
    171        /* Check for malloc/realloc failure. */
    172        if (f->fTranslit->buffer == nullptr) {
    173        	return nullptr;
    174        }
    175        f->fTranslit->capacity = newlen;
    176    }
    177 
    178    /* Now, copy any data over */
    179    u_strncpy(f->fTranslit->buffer + f->fTranslit->length,
    180        src,
    181        *count);
    182    f->fTranslit->length += *count;
    183 
    184    /* Now, translit in place as much as we can  */
    185    if(flush == false)
    186    {
    187        textLength = f->fTranslit->length;
    188        pos.contextStart = 0;
    189        pos.contextLimit = textLength;
    190        pos.start        = 0;
    191        pos.limit        = textLength;
    192 
    193        utrans_transIncrementalUChars(f->fTranslit->translit,
    194            f->fTranslit->buffer, /* because we shifted */
    195            &textLength,
    196            f->fTranslit->capacity,
    197            &pos,
    198            &status);
    199 
    200        /* now: start/limit point to the transliterated text */
    201        /* Transliterated is [buffer..pos.start) */
    202        *count            = pos.start;
    203        f->fTranslit->pos = pos.start;
    204        f->fTranslit->length = pos.limit;
    205 
    206        return f->fTranslit->buffer;
    207    }
    208    else
    209    {
    210        textLength = f->fTranslit->length;
    211        textLimit = f->fTranslit->length;
    212 
    213        utrans_transUChars(f->fTranslit->translit,
    214            f->fTranslit->buffer,
    215            &textLength,
    216            f->fTranslit->capacity,
    217            0,
    218            &textLimit,
    219            &status);
    220 
    221        /* out: converted len */
    222        *count = textLimit;
    223 
    224        /* Set pointers to 0 */
    225        f->fTranslit->pos = 0;
    226        f->fTranslit->length = 0;
    227 
    228        return f->fTranslit->buffer;
    229    }
    230 }
    231 
    232 #endif
    233 
    234 void
    235 ufile_flush_translit(UFILE *f)
    236 {
    237 #if !UCONFIG_NO_TRANSLITERATION
    238    if((!f)||(!f->fTranslit))
    239        return;
    240 #endif
    241 
    242    u_file_write_flush(nullptr, 0, f, false, true);
    243 }
    244 
    245 
    246 void
    247 ufile_flush_io(UFILE *f)
    248 {
    249  if((!f) || (!f->fFile)) {
    250    return; /* skip if no file */
    251  }
    252 
    253  u_file_write_flush(nullptr, 0, f, true, false);
    254 }
    255 
    256 
    257 void
    258 ufile_close_translit(UFILE *f)
    259 {
    260 #if !UCONFIG_NO_TRANSLITERATION
    261    if((!f)||(!f->fTranslit))
    262        return;
    263 #endif
    264 
    265    ufile_flush_translit(f);
    266 
    267 #if !UCONFIG_NO_TRANSLITERATION
    268    if(f->fTranslit->translit)
    269        utrans_close(f->fTranslit->translit);
    270 
    271    if(f->fTranslit->buffer)
    272    {
    273        uprv_free(f->fTranslit->buffer);
    274    }
    275 
    276    uprv_free(f->fTranslit);
    277    f->fTranslit = nullptr;
    278 #endif
    279 }
    280 
    281 
    282 /* Input/output */
    283 
    284 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    285 u_fputs(const char16_t *s,
    286        UFILE        *f)
    287 {
    288    int32_t count = u_file_write(s, u_strlen(s), f);
    289    count += u_file_write(DELIMITERS, DELIMITERS_LEN, f);
    290    return count;
    291 }
    292 
    293 U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    294 u_fputc(UChar32      uc,
    295        UFILE        *f)
    296 {
    297    char16_t buf[2];
    298    int32_t idx = 0;
    299    UBool isError = false;
    300 
    301    U16_APPEND(buf, idx, UPRV_LENGTHOF(buf), uc, isError);
    302    if (isError) {
    303        return U_EOF;
    304    }
    305    return u_file_write(buf, idx, f) == idx ? uc : U_EOF;
    306 }
    307 
    308 
    309 U_CFUNC int32_t U_EXPORT2
    310 u_file_write_flush(const char16_t *chars,
    311                   int32_t     count,
    312                   UFILE       *f,
    313                   UBool       flushIO,
    314                   UBool       flushTranslit)
    315 {
    316    /* Set up conversion parameters */
    317    UErrorCode  status       = U_ZERO_ERROR;
    318    const char16_t *mySource    = chars;
    319    const char16_t *mySourceBegin;
    320    const char16_t *mySourceEnd;
    321    char        charBuffer[UFILE_CHARBUFFER_SIZE];
    322    char        *myTarget   = charBuffer;
    323    int32_t     written      = 0;
    324    int32_t     numConverted = 0;
    325 
    326    if (count < 0) {
    327        count = u_strlen(chars);
    328    }
    329 
    330 #if !UCONFIG_NO_TRANSLITERATION
    331    if((f->fTranslit) && (f->fTranslit->translit))
    332    {
    333        /* Do the transliteration */
    334        mySource = u_file_translit(f, chars, &count, flushTranslit);
    335    }
    336 #endif
    337 
    338    /* Write to a string. */
    339    if (!f->fFile) {
    340        int32_t charsLeft = (int32_t)(f->str.fLimit - f->str.fPos);
    341        if (flushIO && charsLeft > count) {
    342            count++;
    343        }
    344        written = ufmt_min(count, charsLeft);
    345        u_strncpy(f->str.fPos, mySource, written);
    346        f->str.fPos += written;
    347        return written;
    348    }
    349 
    350    mySourceEnd = mySource + count;
    351 
    352    /* Perform the conversion in a loop */
    353    do {
    354        mySourceBegin = mySource; /* beginning location for this loop */
    355        status     = U_ZERO_ERROR;
    356        if(f->fConverter != nullptr) { /* We have a valid converter */
    357            ucnv_fromUnicode(f->fConverter,
    358                &myTarget,
    359                charBuffer + UFILE_CHARBUFFER_SIZE,
    360                &mySource,
    361                mySourceEnd,
    362                nullptr,
    363                flushIO,
    364                &status);
    365        } else { /*weiv: do the invariant conversion */
    366            int32_t convertChars = (int32_t) (mySourceEnd - mySource); 
    367            if (convertChars > UFILE_CHARBUFFER_SIZE) { 
    368                convertChars = UFILE_CHARBUFFER_SIZE; 
    369                status = U_BUFFER_OVERFLOW_ERROR; 
    370            } 
    371            u_UCharsToChars(mySource, myTarget, convertChars); 
    372            mySource += convertChars; 
    373            myTarget += convertChars; 
    374        }
    375        numConverted = (int32_t)(myTarget - charBuffer);
    376 
    377        if (numConverted > 0) {
    378            /* write the converted bytes */
    379            fwrite(charBuffer,
    380                sizeof(char),
    381                numConverted,
    382                f->fFile);
    383 
    384            written     += (int32_t) (mySource - mySourceBegin);
    385        }
    386        myTarget     = charBuffer;
    387    }
    388    while(status == U_BUFFER_OVERFLOW_ERROR);
    389 
    390    /* return # of chars written */
    391    return written;
    392 }
    393 
    394 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    395 u_file_write(    const char16_t  *chars,
    396             int32_t        count,
    397             UFILE         *f)
    398 {
    399    return u_file_write_flush(chars,count,f,false,false);
    400 }
    401 
    402 
    403 /* private function used for buffering input */
    404 void
    405 ufile_fill_uchar_buffer(UFILE *f)
    406 {
    407    UErrorCode  status;
    408    const char  *mySource;
    409    const char  *mySourceEnd;
    410    char16_t    *myTarget;
    411    int32_t     bufferSize;
    412    int32_t     maxCPBytes;
    413    int32_t     bytesRead;
    414    int32_t     availLength;
    415    int32_t     dataSize;
    416    char        charBuffer[UFILE_CHARBUFFER_SIZE];
    417    u_localized_string *str;
    418 
    419    if (f->fFile == nullptr) {
    420        /* There is nothing to do. It's a string. */
    421        return;
    422    }
    423 
    424    str = &f->str;
    425    dataSize = static_cast<int32_t>(str->fLimit - str->fPos);
    426    if (f->fFileno == 0 && dataSize > 0) {
    427        /* Don't read from stdin too many times. There is still some data. */
    428        return;
    429    }
    430 
    431    /* shift the buffer if it isn't empty */
    432    if(dataSize != 0) {
    433        u_memmove(f->fUCBuffer, str->fPos, dataSize); /* not accessing beyond memory */
    434    }
    435 
    436 
    437    /* record how much buffer space is available */
    438    availLength = UFILE_UCHARBUFFER_SIZE - dataSize;
    439 
    440    /* Determine the # of codepage bytes needed to fill our char16_t buffer */
    441    /* weiv: if converter is nullptr, we use invariant converter with charwidth = 1)*/
    442    maxCPBytes = availLength / (f->fConverter!=nullptr?(2*ucnv_getMinCharSize(f->fConverter)):1);
    443 
    444    /* Read in the data to convert */
    445    if (f->fFileno == 0) {
    446        /* Special case. Read from stdin one line at a time. */
    447        char *retStr = fgets(charBuffer, ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE), f->fFile);
    448        bytesRead = static_cast<int32_t>(retStr ? uprv_strlen(charBuffer) : 0);
    449    }
    450    else {
    451        /* A normal file */
    452        bytesRead = static_cast<int32_t>(fread(charBuffer,
    453            sizeof(char),
    454            ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE),
    455            f->fFile));
    456    }
    457 
    458    /* Set up conversion parameters */
    459    status      = U_ZERO_ERROR;
    460    mySource    = charBuffer;
    461    mySourceEnd = charBuffer + bytesRead;
    462    myTarget    = f->fUCBuffer + dataSize;
    463    bufferSize  = UFILE_UCHARBUFFER_SIZE;
    464 
    465    if(f->fConverter != nullptr) { /* We have a valid converter */
    466        /* Perform the conversion */
    467        ucnv_toUnicode(f->fConverter,
    468            &myTarget,
    469            f->fUCBuffer + bufferSize,
    470            &mySource,
    471            mySourceEnd,
    472            nullptr,
    473            static_cast<UBool>(feof(f->fFile) != 0),
    474            &status);
    475 
    476    } else { /*weiv: do the invariant conversion */
    477        u_charsToUChars(mySource, myTarget, bytesRead);
    478        myTarget += bytesRead;
    479    }
    480 
    481    /* update the pointers into our array */
    482    str->fPos    = str->fBuffer;
    483    str->fLimit  = myTarget;
    484 }
    485 
    486 U_CAPI char16_t* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    487 u_fgets(char16_t     *s,
    488        int32_t       n,
    489        UFILE        *f)
    490 {
    491    int32_t dataSize;
    492    int32_t count;
    493    char16_t *alias;
    494    const char16_t *limit;
    495    char16_t *sItr;
    496    char16_t currDelim = 0;
    497    u_localized_string *str;
    498 
    499    if (n <= 0) {
    500        /* Caller screwed up. We need to write the null terminatior. */
    501        return nullptr;
    502    }
    503 
    504    /* fill the buffer if needed */
    505    str = &f->str;
    506    if (str->fPos >= str->fLimit) {
    507        ufile_fill_uchar_buffer(f);
    508    }
    509 
    510    /* subtract 1 from n to compensate for the terminator */
    511    --n;
    512 
    513    /* determine the amount of data in the buffer */
    514    dataSize = (int32_t)(str->fLimit - str->fPos);
    515 
    516    /* if 0 characters were left, return 0 */
    517    if (dataSize == 0)
    518        return nullptr;
    519 
    520    /* otherwise, iteratively fill the buffer and copy */
    521    count = 0;
    522    sItr = s;
    523    currDelim = 0;
    524    while (dataSize > 0 && count < n) {
    525        alias = str->fPos;
    526 
    527        /* Find how much to copy */
    528        if (dataSize < (n - count)) {
    529            limit = str->fLimit;
    530        }
    531        else {
    532            limit = alias + (n - count);
    533        }
    534 
    535        if (!currDelim) {
    536            /* Copy UChars until we find the first occurrence of a delimiter character */
    537            while (alias < limit && !IS_FIRST_STRING_DELIMITER(*alias)) {
    538                count++;
    539                *(sItr++) = *(alias++);
    540            }
    541            /* Preserve the newline */
    542            if (alias < limit && IS_FIRST_STRING_DELIMITER(*alias)) {
    543                if (CAN_HAVE_COMBINED_STRING_DELIMITER(*alias)) {
    544                    currDelim = *alias;
    545                }
    546                else {
    547                    currDelim = 1;  /* This isn't a newline, but it's used to say
    548                                    that we should break later. We've checked all
    549                                    possible newline combinations even across buffer
    550                                    boundaries. */
    551                }
    552                count++;
    553                *(sItr++) = *(alias++);
    554            }
    555        }
    556        /* If we have a CRLF combination, preserve that too. */
    557        if (alias < limit) {
    558            if (currDelim && IS_COMBINED_STRING_DELIMITER(currDelim, *alias)) {
    559                count++;
    560                *(sItr++) = *(alias++);
    561            }
    562            currDelim = 1;  /* This isn't a newline, but it's used to say
    563                            that we should break later. We've checked all
    564                            possible newline combinations even across buffer
    565                            boundaries. */
    566        }
    567 
    568        /* update the current buffer position */
    569        str->fPos = alias;
    570 
    571        /* if we found a delimiter */
    572        if (currDelim == 1) {
    573            /* break out */
    574            break;
    575        }
    576 
    577        /* refill the buffer */
    578        ufile_fill_uchar_buffer(f);
    579 
    580        /* determine the amount of data in the buffer */
    581        dataSize = (int32_t)(str->fLimit - str->fPos);
    582    }
    583 
    584    /* add the terminator and return s */
    585    *sItr = 0x0000;
    586    return s;
    587 }
    588 
    589 U_CFUNC UBool U_EXPORT2
    590 ufile_getch(UFILE *f, char16_t *ch)
    591 {
    592    UBool isValidChar = false;
    593 
    594    *ch = U_EOF;
    595    /* if we have an available character in the buffer, return it */
    596    if(f->str.fPos < f->str.fLimit){
    597        *ch = *(f->str.fPos)++;
    598        isValidChar = true;
    599    }
    600    else {
    601        /* otherwise, fill the buffer and return the next character */
    602        if(f->str.fPos >= f->str.fLimit) {
    603            ufile_fill_uchar_buffer(f);
    604        }
    605        if(f->str.fPos < f->str.fLimit) {
    606            *ch = *(f->str.fPos)++;
    607            isValidChar = true;
    608        }
    609    }
    610    return isValidChar;
    611 }
    612 
    613 U_CAPI char16_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    614 u_fgetc(UFILE        *f)
    615 {
    616    char16_t ch;
    617    ufile_getch(f, &ch);
    618    return ch;
    619 }
    620 
    621 U_CFUNC UBool U_EXPORT2
    622 ufile_getch32(UFILE *f, UChar32 *c32)
    623 {
    624    UBool isValidChar = false;
    625    u_localized_string *str;
    626 
    627    *c32 = U_EOF;
    628 
    629    /* Fill the buffer if it is empty */
    630    str = &f->str;
    631    if (str->fPos + 1 >= str->fLimit) {
    632        ufile_fill_uchar_buffer(f);
    633    }
    634 
    635    /* Get the next character in the buffer */
    636    if (str->fPos < str->fLimit) {
    637        *c32 = *(str->fPos)++;
    638        if (U_IS_LEAD(*c32)) {
    639            if (str->fPos < str->fLimit) {
    640                char16_t c16 = *(str->fPos)++;
    641                *c32 = U16_GET_SUPPLEMENTARY(*c32, c16);
    642                isValidChar = true;
    643            }
    644            else {
    645                *c32 = U_EOF;
    646            }
    647        }
    648        else {
    649            isValidChar = true;
    650        }
    651    }
    652 
    653    return isValidChar;
    654 }
    655 
    656 U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    657 u_fgetcx(UFILE        *f)
    658 {
    659    UChar32 ch;
    660    ufile_getch32(f, &ch);
    661    return ch;
    662 }
    663 
    664 U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    665 u_fungetc(UChar32        ch,
    666    UFILE        *f)
    667 {
    668    u_localized_string *str;
    669 
    670    str = &f->str;
    671 
    672    /* if we're at the beginning of the buffer, sorry! */
    673    if (str->fPos == str->fBuffer
    674        || (U_IS_LEAD(ch) && (str->fPos - 1) == str->fBuffer))
    675    {
    676        ch = U_EOF;
    677    }
    678    else {
    679        /* otherwise, put the character back */
    680        /* Remember, read them back on in the reverse order. */
    681        if (U_IS_LEAD(ch)) {
    682            if (*--(str->fPos) != U16_TRAIL(ch)
    683                || *--(str->fPos) != U16_LEAD(ch))
    684            {
    685                ch = U_EOF;
    686            }
    687        }
    688        else if (*--(str->fPos) != ch) {
    689            ch = U_EOF;
    690        }
    691    }
    692    return ch;
    693 }
    694 
    695 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    696 u_file_read(    char16_t     *chars,
    697    int32_t        count,
    698    UFILE         *f)
    699 {
    700    int32_t dataSize;
    701    int32_t read = 0;
    702    u_localized_string *str = &f->str;
    703 
    704    do {
    705 
    706        /* determine the amount of data in the buffer */
    707        dataSize = (int32_t)(str->fLimit - str->fPos);
    708        if (dataSize <= 0) {
    709            /* fill the buffer */
    710            ufile_fill_uchar_buffer(f);
    711            dataSize = (int32_t)(str->fLimit - str->fPos);
    712        }
    713 
    714        /* Make sure that we don't read too much */
    715        if (dataSize > (count - read)) {
    716            dataSize = count - read;
    717        }
    718 
    719        /* copy the current data in the buffer */
    720        memcpy(chars + read, str->fPos, dataSize * sizeof(char16_t));
    721 
    722        /* update number of items read */
    723        read += dataSize;
    724 
    725        /* update the current buffer position */
    726        str->fPos += dataSize;
    727    }
    728    while (dataSize != 0 && read < count);
    729 
    730    return read;
    731 }
    732 #endif