| OLD | NEW |
| (Empty) |
| 1 // Copyright 2003-2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 | |
| 16 #include "omaha/base/file_reader.h" | |
| 17 #include "omaha/base/debug.h" | |
| 18 | |
| 19 namespace omaha { | |
| 20 | |
| 21 FileReader::FileReader() | |
| 22 : file_is_open_(false), | |
| 23 buffered_byte_count_(0), | |
| 24 current_position_(0), | |
| 25 file_buffer_size_(0), | |
| 26 is_unicode_(false) {} | |
| 27 | |
| 28 FileReader::~FileReader() { | |
| 29 if (file_is_open_) { | |
| 30 file_.Close(); | |
| 31 file_is_open_ = false; | |
| 32 } | |
| 33 } | |
| 34 | |
| 35 HRESULT FileReader::Init(const TCHAR* file_name, size_t buffer_size) { | |
| 36 ASSERT1(file_name); | |
| 37 ASSERT1(buffer_size); | |
| 38 file_buffer_size_ = buffer_size; | |
| 39 file_buffer_.reset(new byte[file_buffer_size()]); | |
| 40 HRESULT hr = file_.OpenShareMode(file_name, false, false, FILE_SHARE_WRITE | | |
| 41 FILE_SHARE_READ); | |
| 42 file_is_open_ = SUCCEEDED(hr); | |
| 43 is_unicode_ = false; | |
| 44 | |
| 45 if (FAILED(hr)) { | |
| 46 return hr; | |
| 47 } | |
| 48 | |
| 49 hr = file_.SeekToBegin(); | |
| 50 if (FAILED(hr)) { | |
| 51 return hr; | |
| 52 } | |
| 53 | |
| 54 const int unicode_header_length = 2; | |
| 55 | |
| 56 char buf[unicode_header_length] = {0}; | |
| 57 uint32 bytes_read = 0; | |
| 58 hr = file_.Read(sizeof(buf), reinterpret_cast<byte*>(buf), &bytes_read); | |
| 59 if (FAILED(hr)) { | |
| 60 return hr; | |
| 61 } | |
| 62 | |
| 63 if (bytes_read == sizeof(buf)) { | |
| 64 char unicode_buf[unicode_header_length] = {0xff, 0xfe}; | |
| 65 is_unicode_ = (memcmp(buf, unicode_buf, sizeof(buf)) == 0); | |
| 66 } | |
| 67 | |
| 68 if (!is_unicode_) { | |
| 69 file_.SeekToBegin(); | |
| 70 } | |
| 71 | |
| 72 if (is_unicode_ && (buffer_size < sizeof(WCHAR))) { | |
| 73 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | |
| 74 } | |
| 75 | |
| 76 return S_OK; | |
| 77 } | |
| 78 | |
| 79 HRESULT FileReader::GetNextChar(bool peek, CString* next_char) { | |
| 80 ASSERT1(next_char); | |
| 81 next_char->Empty(); | |
| 82 | |
| 83 // Do we need to read in more of the file? | |
| 84 if (current_position_ >= buffered_byte_count_) { | |
| 85 current_position_ = 0; | |
| 86 if (FAILED(file_.Read(file_buffer_size(), | |
| 87 file_buffer_.get(), | |
| 88 &buffered_byte_count_))) { | |
| 89 // There is no more of the file buffered. | |
| 90 buffered_byte_count_ = 0; | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 // Have we gone past the end of the file? | |
| 95 if (current_position_ >= buffered_byte_count_) { | |
| 96 return E_FAIL; | |
| 97 } | |
| 98 | |
| 99 if (is_unicode_) { | |
| 100 // Need to make sure there are at least 2 characters still in the buffer. | |
| 101 // If we're right at the end of the buffer and there's only one character, | |
| 102 // then we will need to read more from the file. | |
| 103 | |
| 104 if (current_position_ + 1 >= buffered_byte_count_) { | |
| 105 // We need one more byte to make a WCHAR. | |
| 106 // Due to the need to peek, we're going to take that byte and put it at | |
| 107 // the beginning of the file_buffer_ and read in as many remaining bytes | |
| 108 // as we can from the file. | |
| 109 | |
| 110 // Copy current (and last) byte to the beginning of the buffer. | |
| 111 file_buffer_[0] = file_buffer_[current_position_]; | |
| 112 | |
| 113 // Reset current_position. | |
| 114 current_position_ = 0; | |
| 115 | |
| 116 if (SUCCEEDED(file_.Read(file_buffer_size() - 1, | |
| 117 file_buffer_.get() + 1, | |
| 118 &buffered_byte_count_))) { | |
| 119 // Incrememt count to deal with byte we pre-filled at offset 0. | |
| 120 buffered_byte_count_++; | |
| 121 } else { | |
| 122 // We've got a Unicode file with an extra byte. We're going to drop the | |
| 123 // byte and call it end of file. | |
| 124 buffered_byte_count_ = 0; | |
| 125 return E_FAIL; | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 // Get the next character. | |
| 130 char c1 = file_buffer_[current_position_]; | |
| 131 ++current_position_; | |
| 132 char c2 = file_buffer_[current_position_]; | |
| 133 ++current_position_; | |
| 134 | |
| 135 if (peek) { | |
| 136 // Reset the current position pointer backwards if we're peeking. | |
| 137 current_position_ -= 2; | |
| 138 } | |
| 139 | |
| 140 WCHAR c = (static_cast<WCHAR>(c2) << 8) | static_cast<WCHAR>(c1); | |
| 141 | |
| 142 *next_char = c; | |
| 143 } else { | |
| 144 char c = file_buffer_[current_position_]; | |
| 145 if (!peek) { | |
| 146 ++current_position_; | |
| 147 } | |
| 148 *next_char = c; | |
| 149 } | |
| 150 | |
| 151 return S_OK; | |
| 152 } | |
| 153 | |
| 154 HRESULT FileReader::ReadLineString(CString* line) { | |
| 155 ASSERT1(line); | |
| 156 | |
| 157 line->Empty(); | |
| 158 | |
| 159 while (true) { | |
| 160 CString current_char; | |
| 161 HRESULT hr = GetNextChar(false, ¤t_char); | |
| 162 // If we failed to get the next char, we're at the end of the file. | |
| 163 // If the current line is empty, then fail out signalling we're done. | |
| 164 // Otherwise, return the current line and we'll fail out on the next call to | |
| 165 // ReadLine(). | |
| 166 if (FAILED(hr)) { | |
| 167 if (line->IsEmpty()) { | |
| 168 return hr; | |
| 169 } else { | |
| 170 return S_OK; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 // Have we reached end of line? | |
| 175 if (current_char.Compare(_T("\r")) == 0) { | |
| 176 // Seek ahead to see if the next char is "\n" | |
| 177 CString next_char; | |
| 178 GetNextChar(true, &next_char); | |
| 179 if (next_char.Compare(_T("\n")) == 0) { | |
| 180 // Get in the next char too. | |
| 181 GetNextChar(false, &next_char); | |
| 182 } | |
| 183 break; | |
| 184 } else if (current_char.Compare(_T("\n")) == 0) { | |
| 185 break; | |
| 186 } | |
| 187 | |
| 188 line->Append(current_char); | |
| 189 } | |
| 190 | |
| 191 return S_OK; | |
| 192 } | |
| 193 | |
| 194 HRESULT FileReader::ReadLineAnsi(size_t max_len, char* line) { | |
| 195 ASSERT1(line); | |
| 196 ASSERT1(max_len); | |
| 197 | |
| 198 size_t total_len = 0; | |
| 199 | |
| 200 while (true) { | |
| 201 // Do we need to read in more of the file? | |
| 202 if (current_position_ >= buffered_byte_count_) { | |
| 203 current_position_ = 0; | |
| 204 if (FAILED(file_.Read(file_buffer_size(), | |
| 205 file_buffer_.get(), | |
| 206 &buffered_byte_count_))) { | |
| 207 // There is no more of the file buffered. | |
| 208 buffered_byte_count_ = 0; | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 // Have we gone past the end of the file? | |
| 213 if (current_position_ >= buffered_byte_count_) { | |
| 214 break; | |
| 215 } | |
| 216 | |
| 217 // Get the next character. | |
| 218 char c = file_buffer_[current_position_]; | |
| 219 ++current_position_; | |
| 220 | |
| 221 // Have we reached end of line? | |
| 222 // TODO(omaha): if the line is terminated with a \r\n pair then perhaps | |
| 223 // the code should skip the whole pair not only half of it. | |
| 224 if (c == '\n' || c == '\r') { | |
| 225 break; | |
| 226 } | |
| 227 | |
| 228 // Fill up the passed in buffer for the line. | |
| 229 if (total_len < max_len - 1) { | |
| 230 line[total_len] = c; | |
| 231 ++total_len; | |
| 232 } | |
| 233 } | |
| 234 // Terminate the passed in buffer. | |
| 235 ASSERT1(total_len < max_len); | |
| 236 line[total_len] = '\0'; | |
| 237 | |
| 238 // If we are out of bytes and we didn't read in any bytes. | |
| 239 // then fail signaling end of file. | |
| 240 if (!buffered_byte_count_ && !total_len) { | |
| 241 return E_FAIL; | |
| 242 } | |
| 243 | |
| 244 return S_OK; | |
| 245 } | |
| 246 | |
| 247 } // namespace omaha | |
| 248 | |
| OLD | NEW |