// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Eduardo Aguiar
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "sector_reader_impl_dynamic.h"
#include "imagefile_impl.h"
#include <mobius/io/file.h>

namespace mobius
{
namespace imagefile
{
namespace vhd
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Create sector_reader from imagefile_impl
//! \param impl imagefile_impl object
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sector_reader_impl_dynamic::sector_reader_impl_dynamic (const imagefile_impl& impl)
 : sectors_ (impl.get_sectors ()),
   sector_size_ (impl.get_sector_size ()),
   block_size_ (impl.get_block_size ()),
   block_allocation_table_ (impl.get_block_allocation_table ())
{
  sectors_per_block_ = block_size_ / sector_size_;
  bitmap_size_ = sectors_per_block_ / 8;

  std::uint32_t remaining = bitmap_size_ % sector_size_;
  
  if (remaining)
    bitmap_size_ = bitmap_size_ + sector_size_ - remaining;
  
  // open reader
  mobius::io::file f (impl.get_url ());
  stream_ = f.new_reader ();
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Check if sector is available
//! \param sector Sector
//! \return true/false
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool
sector_reader_impl_dynamic::is_available (sector_type sector)
{
  return bool (sector < sectors_);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Read sector
//! \param sector Sector
//! \return Data from sector
//
// Block is composed of Bitmap array + Data. The bitmap array seems to be
// filled with 1's bits, so there is no need to read the bit corresponding to
// the sector we want to read.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mobius::bytearray
sector_reader_impl_dynamic::read (sector_type sector)
{
  std::uint32_t block_idx = sector / sectors_per_block_;
  std::uint32_t sector_idx = sector % sectors_per_block_;
  std::uint32_t sector_offset = block_allocation_table_[block_idx];
  
  if (sector_offset == 0xffffffff)
    return mobius::bytearray (sector_size_);

  std::uint64_t offset = std::uint64_t (sector_offset + sector_idx) * sector_size_ + bitmap_size_;
  
  stream_.seek (offset);
  return stream_.read (sector_size_);
}

} // namespace vhd
} // namespace imagefile
} // namespace mobius
