/* Copyright 2008 David Moews (dmoews@fastmail.fm)

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 of the License, 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#include <cassert>
#include <cstddef>
#include <istream>
#include <limits>

#include "Types.h"
#include "io.h"

// Returns succ/failure.
bool file_size(std::istream &i, u32 block_size, u32 *p_size)
{
  i.seekg(0, std::ios::end);
  if (i.fail())
     return false;

  std::istream::off_type ofs = i.tellg();

  if (i.fail())
     return false;

  if (ofs % block_size != 0u)
     return false;

  ofs /= block_size;

  if ((double)ofs > 0.99 * (double)std::numeric_limits<u32>::max())
     return false;

  if (p_size)
     *p_size = ofs;
  return true;
}

// Returns succ/failure
bool read_sector(std::istream &i, u32 sector_number, u32 sector_size, 
                 char p_cs[2048])
{
  assert(p_cs != NULL);

  i.seekg((std::istream::off_type)sector_number * 
          (std::istream::off_type)sector_size, std::ios::beg);
  if (i.fail())
     return false;

  i.read(p_cs, 2048u);

  if (i.fail())
     return false;

  return true;
}

// Returns succ/failure
bool read_blocks(std::istream &i, u32 block_number, u32 number_of_blocks,
                 u32 block_size, char *p_cs)
{
  assert(p_cs != NULL);

  i.seekg((std::istream::off_type)block_number * 
          (std::istream::off_type)block_size, std::ios::beg);
  if (i.fail())
     return false;

  while (number_of_blocks != 0)
  {
    u32 n = 0;

    if ((double)number_of_blocks * (double)block_size < (double)1.5e9)
       n = number_of_blocks;
    else
       n = 1073741824ul / block_size;

    i.read(p_cs, (std::streamsize)n * (std::streamsize)block_size);
    if (i.fail())
       return false;

    p_cs += (std::size_t)n * (std::size_t)block_size;
    number_of_blocks -= n;
  }

  return true;
}
