Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637//// read.cpp//// Copyright (c) Microsoft Corporation. All rights reserved.//// Defines _read(), which reads bytes from a file.//#include <corecrt_internal_lowio.h>
// Lookup table for UTF-8 lead bytes// Probably preferable to just ask if the bits are set than use an entire// table, however the macros using this were #defined in the header so// removing this extern table would break apps compiled to an earlier verison.// 1 for pattern 110xxxxx - 1 trailbyte// 2 for pattern 1110xxxx - 2 trailbytes// 3 for pattern 11110xxx - 3 trailbytes// 0 for everything else, including invalid patterns.// We return 0 for invalid patterns because we rely on MultiByteToWideChar to// do the validations.extern "C" { char _lookuptrailbytes[256] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0}; }
static void store_lookahead(int const fh, char const c) throw(){ _pipe_lookahead(fh)[0] = c;}
static void store_lookahead(int const fh, wchar_t const c) throw(){ char const* const byte_pointer = reinterpret_cast<char const*>(&c); _pipe_lookahead(fh)[0] = byte_pointer[0]; _pipe_lookahead(fh)[1] = byte_pointer[1]; _pipe_lookahead(fh)[2] = LF; // Mark as empty}
static int __cdecl translate_utf16_from_console_nolock( int const fh, _Inout_updates_(count) wchar_t* const buffer, size_t const count ) throw(){ // The translation can be performend in-place, because we are converting // CRLF sequences into LF, so the resulting text will never be longer than // any corresponding source text. wchar_t* const buffer_end = buffer + count;
wchar_t* source_it = buffer; wchar_t* result_it = buffer;
while (source_it < buffer_end) { // If at any point during translation we encounter a Ctrl+Z, we stop // translating immediately: if (*source_it == CTRLZ) { _osfile(fh) |= FEOFLAG; break; }
// When a CR character is encountered, we must check to see if the next // character is an LF. If it is, then we skip the CR and copy only the // LF: if (*source_it == CR && source_it + 1 < buffer_end && *(source_it + 1) == LF) { source_it += 2; *result_it++ = LF; continue; }
// Otherwise, we just copy the character: *result_it++ = *source_it++; }
// Return the number of bytes that we translated: return static_cast<int>((result_it - buffer) * sizeof(wchar_t));}
template <typename Character>static int __cdecl translate_text_mode_nolock( _In_ int const fh, _Pre_writable_size_(count) _Post_readable_byte_size_(return) Character* const buffer, _In_ size_t const count ) throw(){ HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh));
// If there is an LF at the beginning of the buffer, set the CRLF flag: if (count != 0 && *buffer == LF) { _osfile(fh) |= FCRLF; } else { _osfile(fh) &= ~FCRLF; }
// The translation can be performend in-place, because we are converting // CRLF sequences into LF, so the resulting text will never be longer than // any corresponding source text. Character* const buffer_end = buffer + count;
Character* source_it = buffer; Character* result_it = buffer;
while (source_it < buffer_end) { // If during translation we encounter a Ctrl+Z, we stop translating // immeidately. For devices, we need to just set the Ctrl+Z flag; // for other files, we just copy the Ctrl+Z as a normal character // before returning: if (*source_it == CTRLZ) { if ((_osfile(fh) & FDEV) == 0) { _osfile(fh) |= FEOFLAG; } else { *result_it++ = *source_it++; }
break; }
// If the character is not a CR, then we can simply copy it: if (*source_it != CR) { *result_it++ = *source_it++; continue; }
// Otherwise, the character is a CR. We need to look-ahead to see if // the next character is an LF, so that we can perform the CRLF => LF // translation. First, handle the easy case where the CR does not // appear at the end of the buffer: if (source_it + 1 < buffer_end) { if (*(source_it + 1) == LF) { source_it += 2; *result_it++ = LF; // Convert CRLF => LF } else { *result_it++ = *source_it++; }
continue; }
// This is the hard case: The CR is at the end of the buffer. We need // to peek ahead to see if the next character is an LF: ++source_it;
Character peek; DWORD peek_size; if (!ReadFile(os_handle, &peek, sizeof(peek), &peek_size, nullptr) || peek_size == 0) { // We couldn't peek ahead; just store the CR: *result_it++ = CR; continue; }
// The peek succeeded. What we do next depends on whether the file is // seekable or not. First we handle the case where the file does not // allow seeking: if (_osfile(fh) & (FDEV | FPIPE)) { // If the peek character is an LF, then we just need to copy that // character to the output buffer: if (peek == LF) { *result_it++ = LF; } // Otherwise, it was some other character. We need to write the CR // to the output buffer, then we need to store the peek character // for later retrieval: else { *result_it++ = CR; store_lookahead(fh, peek); } } // If the file does allow seeking, then we handle the peek differently. // For seekable files, we translate the CRLF => LF by eliminating the // CR. If the peek character is an LF, we simply do not write it to // the output buffer; instead, we will seek backwards to unpeek the // character, then let the LF get retrieved during the next call to // read(). else { // However, if the buffer is currenty empty, then this is a one- // character read, so we store the LF in order that we make progress if (peek == LF && result_it == buffer) { *result_it++ = LF; } // Otherwise, we do what is described above: we seek backwards and // write the CR if and only if the peek character was not an LF: else { _lseeki64_nolock(fh, -1 * static_cast<int>(sizeof(Character)), FILE_CURRENT); if (peek != LF) { *result_it++ = CR; } } } }
// Return the number of bytes that we translated: return static_cast<int>((result_it - buffer) * sizeof(Character));}
_Success_(return != -1)static int __cdecl translate_ansi_or_utf8_nolock( int const fh, _In_reads_(source_count) char* const source_buffer, size_t const source_count, _Pre_writable_size_(result_count) _Post_readable_byte_size_(return) wchar_t* const result_buffer, size_t const result_count ) throw(){ int const text_mode_translation_result_size = translate_text_mode_nolock(fh, source_buffer, source_count);
// If we read no characters, then we are done: if (text_mode_translation_result_size == 0) { return 0; }
// If the file is open in ANSI mode, then no further translation is // required; we can simply return the number of bytes that we read. // Even though there is no translation, there may still be // characters in the buffer due to CRLF translation (a CR without // a LF would 'unget' the would-be LF). // text_mode_translation_result_size has already been adjusted for // CRLF translation by translate_text_mode_nolock(). if (_textmode(fh) == __crt_lowio_text_mode::ansi) { return text_mode_translation_result_size; }
// Otherwise, the file is open in UTF-8 mode and we read a nonzero number // of characters. We need to translate from UTF-8 to UTF-16. To do this, // we first need to hunt for the end of the translatable buffer. This may // not be result_it, because we may have read a partial multibyte UTF-8 // character. char* result_it = source_buffer + text_mode_translation_result_size - 1;
// If the last character is an independent character, then we can // translate the entire buffer: if (_utf8_is_independent(*result_it)) { ++result_it; // Reset the result_it } // Otherwise, we have to find the end of the last full UTF-8 character // that was read: else { // Walk backwards from the end of the buffer until we find a lead byte: unsigned counter = 1; while (!_utf8_is_leadbyte(*result_it) && counter <= 4 && result_it >= source_buffer) { --result_it; ++counter; }
// Now that we've found the last lead byte, determine whether the // character is complete or incomplete. We compute the number of // trailbytes... unsigned const trailbyte_count = _utf8_no_of_trailbytes(static_cast<const unsigned char>(*result_it)); if (trailbyte_count == 0) { // Oh, apparently that wasn't a lead byte; the file contains invalid // UTF-8 character sequences: errno = EILSEQ; return -1; }
// If the lead byte plus the remaining bytes form a full set, then we // can translate the entire buffer: if (trailbyte_count + 1 == counter) { result_it += counter; } // Otherwise, the last character is incomplete, so we will not include // this character in the result. We unget the last characters, either // by seeking backwards if the file is seekable, or by buffering the // characters. Note that result_it currently points one-past-the-end // of the translatable buffer, because it points to the lead byte of // the partially read character. else { // If the file does not support seeking, buffer the characters: if (_osfile(fh) & (FDEV | FPIPE)) { _pipe_lookahead(fh)[0] = *result_it++;
if (counter >= 2) { _pipe_lookahead(fh)[1] = *result_it++; }
if (counter == 3) { _pipe_lookahead(fh)[2] = *result_it++; }
// Now that we've buffered the characters, seek the end iterator // back to the actual end of the translatable sequence: result_it -= counter;
} // If the file does support seeking, we can just seek backwards so // that the next read will get the characters directly: else { _lseeki64_nolock(fh, -static_cast<int>(counter), FILE_CURRENT); } } }
// Finally, we can translate the characters into the result buffer: int const characters_translated = static_cast<int>(__acrt_MultiByteToWideChar( CP_UTF8, 0, source_buffer, static_cast<DWORD>(result_it - source_buffer), result_buffer, static_cast<DWORD>(result_count)));
if (characters_translated == 0) { __acrt_errno_map_os_error(GetLastError()); return -1; }
_utf8translations(fh) = (characters_translated != static_cast<int>(result_it - source_buffer));
// MultiByteToWideChar returns the number of wide characters that // it produced; we need to return the number of bytes: return characters_translated * sizeof(wchar_t);}
// Reads bytes from a file. This function attempts to read enough bytes to fill// the provided buffer. If the file is in text mode, CRLF sequences are mapped// to LF, thus affecting the number of characters read. This mapping does not// affect the file pointer.//// Returns the number of bytes read, which may be less than the number of bytes// requested if EOF was reached or if the file is in text mode. Returns -1 and// sets errno on failure.extern "C" int __cdecl _read(int const fh, void* const buffer, unsigned const buffer_size){ _CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN(buffer_size <= INT_MAX, EINVAL, -1);
__acrt_lowio_lock_fh(fh); int result = -1; __try { if ((_osfile(fh) & FOPEN) == 0) { errno = EBADF; _doserrno = 0; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); __leave; }
result = _read_nolock(fh, buffer, buffer_size); } __finally { __acrt_lowio_unlock_fh(fh); } __endtry return result;}
extern "C" int __cdecl _read_nolock( int const fh, void* const result_buffer, unsigned const result_buffer_size ){ _CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN(result_buffer_size <= INT_MAX, EINVAL, -1);
// If there is no data to be written or if the file is at EOF, no work to do: if (result_buffer_size == 0 || (_osfile(fh) & FEOFLAG)) return 0;
_VALIDATE_CLEAR_OSSERR_RETURN(result_buffer != nullptr, EINVAL, -1);
HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh)); __crt_lowio_text_mode const text_mode = _textmode(fh);
__crt_unique_heap_ptr<char> owned_internal_buffer;
char* internal_buffer; unsigned internal_buffer_remaining; switch (text_mode) { case __crt_lowio_text_mode::utf8: // For UTF-8 files, we need two buffers, because after reading we need // to convert the text into Unicode. MultiByteToWideChar doesn't do // in-place conversions. // // The multibyte to wide character conversion may double the size of the // text, hence we halve the size here. // // Since we are reading a UTF-8 stream, the number of bytes read may // vary from 'size' characters to 'size/4' characters. For this reason, // if we need to read 'size' characters, we will allocate an MBCS buffer // of size 'size'. In case the size is zero, we will use four as a // minimum value. This will make sure we don't overflow when we read // from a pipe. // // In this case, the number of wide characters that we can read is // size / 2. This means that we require a buffer of size size / 2.
// For UTF-8 the count always needs to be an even number: _VALIDATE_CLEAR_OSSERR_RETURN(result_buffer_size % 2 == 0, EINVAL, -1);
internal_buffer_remaining = (result_buffer_size / 2) < 4 ? 4 : (result_buffer_size/2);
owned_internal_buffer = _malloc_crt_t(char, internal_buffer_remaining); internal_buffer = owned_internal_buffer.get(); if (!internal_buffer) { errno = ENOMEM; _doserrno = ERROR_NOT_ENOUGH_MEMORY; return -1; }
_startpos(fh) = _lseeki64_nolock(fh, 0, FILE_CURRENT); break;
case __crt_lowio_text_mode::utf16le: // For UTF-16 the count always needs to be an even number: _VALIDATE_CLEAR_OSSERR_RETURN((result_buffer_size % 2) == 0, EINVAL, -1);
// For UTF-16 files, we can directly use the input buffer: internal_buffer_remaining = result_buffer_size; internal_buffer = static_cast<char*>(result_buffer); break;
default: // For ANSI files, we can directly use the input buffer: internal_buffer_remaining = result_buffer_size; internal_buffer = static_cast<char*>(result_buffer); break; }
wchar_t* wide_internal_buffer = reinterpret_cast<wchar_t*>(internal_buffer);
int bytes_read = 0;
// We may have buffered look-ahead characters during the last read. If // so, read them into the buffer and set the look-ahead buffers back to // empty state (with the value of LF): // // CRT_REFACTOR This look-ahead buffering could use additional work, but // will require nonlocal changes, so that work is not included in this // changeset. if ((_osfile(fh) & (FPIPE | FDEV)) && _pipe_lookahead(fh)[0] != LF && internal_buffer_remaining != 0) { *internal_buffer++ = _pipe_lookahead(fh)[0]; ++bytes_read; --internal_buffer_remaining; _pipe_lookahead(fh)[0] = LF;
// For UTF-16, there may be an additional look-ahead character // bufferred. For UTF-8, there may be two more: if (text_mode != __crt_lowio_text_mode::ansi && _pipe_lookahead(fh)[1] != LF && internal_buffer_remaining != 0) { *internal_buffer++ = _pipe_lookahead(fh)[1]; ++bytes_read; --internal_buffer_remaining; _pipe_lookahead(fh)[1] = LF;
if (text_mode == __crt_lowio_text_mode::utf8 && _pipe_lookahead(fh)[2] != LF && internal_buffer_remaining != 0) { *internal_buffer++ = _pipe_lookahead(fh)[2]; ++bytes_read; --internal_buffer_remaining; _pipe_lookahead(fh)[2] = LF; } } }
DWORD console_mode; bool const from_console = _isatty(fh) && (_osfile(fh) & FTEXT) && GetConsoleMode(os_handle, &console_mode);
// Read the data directly from the console: if (from_console && text_mode == __crt_lowio_text_mode::utf16le) { DWORD console_characters_read; if (!ReadConsoleW( os_handle, internal_buffer, internal_buffer_remaining / sizeof(wchar_t), &console_characters_read, nullptr)) { __acrt_errno_map_os_error(GetLastError()); return -1; }
// In UTF-16 mode, the return value is the actual number of wide // characters read; we need the number of bytes: bytes_read += console_characters_read * sizeof(wchar_t); } // Otherwise, read the data from the file normally: else { DWORD bytes_read_from_file; if (!ReadFile( os_handle, internal_buffer, internal_buffer_remaining, &bytes_read_from_file, nullptr ) || bytes_read_from_file > result_buffer_size) { DWORD const last_error = GetLastError(); if (last_error == ERROR_ACCESS_DENIED) { // ERROR_ACCESS_DENIED occurs if the file is open with the wrong // read/write mode. For this error, we should return EBADF, not // the EACCES that will be set by __acrt_errno_map_os_error: errno = EBADF; _doserrno = last_error; return -1;
} else if (last_error == ERROR_BROKEN_PIPE) { // Return 0 if ERROR_BROKEN_PIPE occurs. It means the handle is // a read handle on a pipe for which all write handles have been // closed and all data has been read: return 0; } else { // Otherwise, map the error normally and return: __acrt_errno_map_os_error(last_error); return -1; } }
bytes_read += bytes_read_from_file; }
// If the file is open in binary mode, no translation is required, so we // can skip all of the rest of this function: if ((_osfile(fh) & FTEXT) == 0) return bytes_read;
// Perform the CRLF => LF translation and convert to the required // encoding (UTF-8 must be converted to UTF-16). This first case // handles UTF-8 and ANSI: if (text_mode != __crt_lowio_text_mode::utf16le) { return translate_ansi_or_utf8_nolock( fh, internal_buffer, bytes_read, static_cast<wchar_t*>(result_buffer), result_buffer_size / sizeof(wchar_t)); }
// The text mode is __crt_lowio_text_mode::utf16le and we are reading from the // console: else if (from_console) { return translate_utf16_from_console_nolock( fh, wide_internal_buffer, bytes_read / sizeof(wchar_t)); } // Otherwise, the text mode is __crt_lowio_text_mode::utf16le and we are NOT // reading from the console: else { return translate_text_mode_nolock( fh, wide_internal_buffer, bytes_read / sizeof(wchar_t)); }}