// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 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 "filesystem_impl_iso.h"
#include <mobius/decoder/data_decoder.h>
#include <mobius/string_functions.h>
#include <cstdio>

#include <iostream>

namespace mobius
{
namespace filesystem
{
static constexpr int SYSTEM_AREA_SIZE = 32768;

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief check if stream contains an instance of ISO9660 filesystem
//! \param reader stream reader
//! \param offset offset from the beginning of the stream
//! \return true/false
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool
filesystem_impl_iso::is_instance (mobius::io::reader reader, std::uint64_t offset)
{

  reader.seek (offset + SYSTEM_AREA_SIZE + 1);
  auto data = reader.read (5);

  return data == "CD001";
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief constructor
//! \param reader stream reader
//! \param offset offset from the beginning of the stream
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
filesystem_impl_iso::filesystem_impl_iso (mobius::io::reader reader, std::uint64_t offset)
  : filesystem_impl_base (reader, offset),
    tsk_adaptor (reader, offset)
{
  // create decoder
  reader.seek (offset + SYSTEM_AREA_SIZE);
  mobius::decoder::data_decoder decoder (reader);

  // decode Primary Volume Descriptor (ECMA-119 8.4)
  decoder.skip (6);
  volume_descr_version_ = decoder.get_uint8 ();
  decoder.skip (1);
  system_id_ = mobius::string::strip (decoder.get_string_by_size (32));
  volume_id_ = mobius::string::strip (decoder.get_string_by_size (32));
  decoder.skip (8);
  volume_space_size_ = decoder.get_uint32_le ();
  decoder.skip (36);
  volume_set_size_ = decoder.get_uint16_le ();
  decoder.skip (2);
  volume_sequence_number_ = decoder.get_uint16_le ();
  decoder.skip (2);
  logical_block_size_ = decoder.get_uint16_le ();
  decoder.skip (2);
  path_table_size_ = decoder.get_uint32_le ();
  decoder.skip (4);
  type_l_path_table_ = decoder.get_uint16_le ();
  decoder.skip (2);
  type_l_optional_path_table_ = decoder.get_uint16_le ();
  decoder.skip (2);
  type_m_path_table_ = decoder.get_uint16_le ();
  decoder.skip (2);
  type_m_optional_path_table_ = decoder.get_uint16_le ();
  decoder.skip (36);
  volume_set_id_ = mobius::string::strip (decoder.get_string_by_size (128));
  publisher_id_ = mobius::string::strip (decoder.get_string_by_size (128));
  data_preparer_id_ = mobius::string::strip (decoder.get_string_by_size (128));
  application_id_ = mobius::string::strip (decoder.get_string_by_size (128));
  copyright_file_id_ = mobius::string::strip (decoder.get_string_by_size (37));
  abstract_file_id_ = mobius::string::strip (decoder.get_string_by_size (37));
  bibliographic_file_id_ = mobius::string::strip (decoder.get_string_by_size (37));
  creation_time_ = decoder.get_iso9660_datetime ();
  last_modification_time_ = decoder.get_iso9660_datetime ();
  expiration_time_ = decoder.get_iso9660_datetime ();
  effective_time_ = decoder.get_iso9660_datetime ();
  file_structure_version_ = decoder.get_uint8 ();

  // derived information
  set_size (static_cast <std::uint64_t> (volume_space_size_) * logical_block_size_);
  set_name ("ISO " + volume_id_);
  set_fs_type ("ISO9660");
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief get metadata
//! \return metadata
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mobius::metadata
filesystem_impl_iso::get_metadata () const
{
  return mobius::metadata
  {
    {
      "type",
      "type",
      "std::string",
      get_type ()
    },
    {
      "offset",
      "offset in bytes",
      "std::uint64_t",
      std::to_string (get_offset ())
    },
    {
      "size",
      "size",
      "size_type",
      std::to_string (get_size ()) + " bytes"
    },
    {
      "name",
      "name",
      "std::string",
      get_name ()
    },
    {
      "fs_type",
      "filesystem type",
      "std::string",
      get_fs_type ()
    },
    {
      "volume_descr_version",
      "volume description version",
      "std::uint8_t",
      std::to_string (get_volume_descr_version ())
    },
    {
      "system_id",
      "system identifier",
      "std::string",
      get_system_id ()
    },
    {
      "volume_id",
      "volume identifier",
      "std::string",
      get_volume_id ()
    },
    {
      "volume_space_size",
      "volume space size",
      "std::uint32_t",
      std::to_string (get_volume_space_size ())
    },
    {
      "volume_set_size",
      "volume set size",
      "std::uint16_t",
      std::to_string (get_volume_set_size ())
    },
    {
      "volume_sequence_number",
      "volume sequence number",
      "std::uint16_t",
      std::to_string (get_volume_sequence_number ())
    },
    {
      "logical_block_size",
      "logical block size",
      "std::uint16_t",
      std::to_string (get_logical_block_size ()) + " bytes"
    },
    {
      "path_table_size",
      "path table size",
      "std::uint32_t",
      std::to_string (get_path_table_size ()) + " bytes"
    },
    {
      "type_l_path_table",
      "location of type L path table",
      "std::uint32_t",
      std::to_string (get_type_l_path_table ())
    },
    {
      "type_l_optional_path_table",
      "location of optional type L path table",
      "std::uint32_t",
      std::to_string (get_type_l_optional_path_table ())
    },
    {
      "type_m_path_table",
      "location of type M path table",
      "std::uint32_t",
      std::to_string (get_type_m_path_table ())
    },
    {
      "type_m_optional_path_table",
      "location of optional type M path table",
      "std::uint32_t",
      std::to_string (get_type_m_optional_path_table ())
    },
    {
      "volume_set_id",
      "volume set identifier",
      "std::string",
      get_volume_set_id ()
    },
    {
      "publisher_id",
      "publisher identifier",
      "std::string",
      get_publisher_id ()
    },
    {
      "data_preparer_id",
      "data preparer identifier",
      "std::string",
      get_data_preparer_id ()
    },
    {
      "application_id",
      "application identifier",
      "std::string",
      get_application_id ()
    },
    {
      "copyright_file_id",
      "copyright file identifier",
      "std::string",
      get_copyright_file_id ()
    },
    {
      "abstract_file_id",
      "abstract file identifier",
      "std::string",
      get_abstract_file_id ()
    },
    {
      "bibliographic_file_id",
      "bibliographic file identifier",
      "std::string",
      get_bibliographic_file_id ()
    },
    {
      "creation_time",
      "volume creation date/time",
      "mobius::datetime::datetime",
      to_string (get_creation_time ())
    },
    {
      "last_modification_time",
      "volume last modification date/time",
      "mobius::datetime::datetime",
      to_string (get_last_modification_time ())
    },
    {
      "expiration_time",
      "volume expiration date/time",
      "mobius::datetime::datetime",
      to_string (get_expiration_time ())
    },
    {
      "effective_time",
      "volume effective date/time",
      "mobius::datetime::datetime",
      to_string (get_effective_time ())
    },
    {
      "file_structure_version",
      "file structure version",
      "std::uint8_t",
      std::to_string (get_file_structure_version ())
    },
  };
}

} // namespace filesystem
} // namespace mobius
