blob: dab21f32cb77a930c325fae1f84ac56723ae3af7 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Internal implementation details for msf_file_stream.h. Not meant to be
// included directly.
#ifndef SYZYGY_MSF_MSF_FILE_STREAM_IMPL_H_
#define SYZYGY_MSF_MSF_FILE_STREAM_IMPL_H_
#include <algorithm>
#include <cstdio>
#include "base/logging.h"
#include "syzygy/msf/msf_decl.h"
namespace msf {
namespace detail {
template <MsfFileType T>
MsfFileStreamImpl<T>::MsfFileStreamImpl(RefCountedFILE* file,
uint32_t length,
const uint32_t* pages,
uint32_t page_size)
: MsfStreamImpl(length), file_(file), page_size_(page_size) {
uint32_t num_pages = (length + page_size - 1) / page_size;
pages_.assign(pages, pages + num_pages);
}
template <MsfFileType T>
MsfFileStreamImpl<T>::~MsfFileStreamImpl() {
}
template <MsfFileType T>
bool MsfFileStreamImpl<T>::ReadBytesAt(size_t pos, size_t count, void* dest) {
DCHECK(dest != NULL);
// Don't read beyond the end of the known stream length.
if (count > length() - pos)
return false;
// Read the stream.
while (count > 0) {
size_t page_index = pos / page_size_;
size_t offset = pos % page_size_;
size_t chunk_size = std::min(count, page_size_ - (pos % page_size_));
if (!ReadFromPage(dest, pages_[page_index], offset, chunk_size))
return false;
count -= chunk_size;
pos += chunk_size;
dest = reinterpret_cast<uint8_t*>(dest) + chunk_size;
}
return true;
}
template <MsfFileType T>
bool MsfFileStreamImpl<T>::ReadFromPage(void* dest,
uint32_t page_num,
size_t offset,
size_t count) {
DCHECK(dest != NULL);
DCHECK(offset + count <= page_size_);
size_t page_offset = page_size_ * page_num;
if (fseek(file_->file(),
static_cast<long>(page_offset + offset),
SEEK_SET) != 0) {
LOG(ERROR) << "Page seek failed";
return false;
}
if (fread(dest, 1, count, file_->file()) != static_cast<size_t>(count)) {
LOG(ERROR) << "Page read failed";
return false;
}
return true;
}
} // namespace detail
} // namespace msf
#endif // SYZYGY_MSF_MSF_FILE_STREAM_IMPL_H_