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 |