| 86 | |
| 87 | |
| 88 | DWORD TextStream::Read(LPTSTR aBuf, DWORD aBufLen, BOOL aReadLine) |
| 89 | { |
| 90 | if (!PrepareToRead()) |
| 91 | return 0; |
| 92 | |
| 93 | DWORD target_used = 0; |
| 94 | LPBYTE src, src_end; |
| 95 | TCHAR dst[UorA(2,4)]; |
| 96 | int src_size; // Size of source character, in bytes. |
| 97 | int dst_size; // Number of code units in destination character. |
| 98 | |
| 99 | UINT codepage = mCodePage; // For performance. |
| 100 | int chr_size = (codepage == CP_UTF16) ? sizeof(WCHAR) : sizeof(CHAR); |
| 101 | |
| 102 | // This is set each iteration based on how many bytes we *need* to have in the buffer. |
| 103 | // Avoid setting it higher than necessary since that can cause undesired effects with |
| 104 | // non-file handles - such as a console waiting for a second line of input when the |
| 105 | // first line is waiting in our buffer. |
| 106 | int next_size = chr_size; |
| 107 | |
| 108 | while (target_used < aBufLen) |
| 109 | { |
| 110 | // Ensure the buffer contains at least one CHAR/WCHAR, or all bytes of the next |
| 111 | // character as determined by a previous iteration of the loop. Note that Read() |
| 112 | // only occurs if the buffer contains less than next_size bytes, and that this |
| 113 | // check does not occur frequently due to buffering and the inner loop below. |
| 114 | if (!ReadAtLeast(next_size) && !mLength) |
| 115 | break; |
| 116 | |
| 117 | // Reset to default (see comments above). |
| 118 | next_size = chr_size; |
| 119 | |
| 120 | // The following macro is used when there is insufficient data in the buffer, |
| 121 | // to determine if more data can possibly be read in. Using mLastRead should be |
| 122 | // faster than AtEOF(), and more reliable with console/pipe handles. |
| 123 | #define LAST_READ_HIT_EOF (mLastRead == 0) |
| 124 | |
| 125 | // Because we copy mPos into a temporary variable here and update mPos at the end of |
| 126 | // each outer loop iteration, it is very important that ReadAtLeast() not be called |
| 127 | // after this point. |
| 128 | src = mPos; |
| 129 | src_end = mBuffer + mLength; // Maint: mLength is in bytes. |
| 130 | |
| 131 | // Ensure there are an even number of bytes in the buffer if we are reading UTF-16. |
| 132 | // This can happen (for instance) when dealing with binary files which also contain |
| 133 | // UTF-16 strings, or if a UTF-16 file is missing its last byte. |
| 134 | if (codepage == CP_UTF16 && ((src_end - src) & 1)) |
| 135 | { |
| 136 | // Try to defer processing of the odd byte until the next byte is read. |
| 137 | --src_end; |
| 138 | // If it's the only byte remaining, the safest thing to do is probably to drop it |
| 139 | // from the stream and output an invalid char so that the error can be detected: |
| 140 | if (src_end == src) |
| 141 | { |
| 142 | mPos = NULL; |
| 143 | mLength = 0; |
| 144 | aBuf[target_used++] = INVALID_CHAR; |
| 145 | break; |
no outgoing calls
no test coverage detected