// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 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_hfs.h"
#include <mobius/decoder/data_decoder.h>

namespace mobius
{
namespace filesystem
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief check if stream contains an instance of vfat filesystem
//! \param reader stream reader
//! \param offset offset from the beginning of the stream
//! \return true/false
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool
filesystem_impl_hfs::is_instance (mobius::io::reader reader, std::uint64_t offset)
{
  reader.seek (offset + 1024);
  auto data = reader.read (2);

  return data == "HX" || data == "H+";
}

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

  // decode data
  signature_ = decoder.get_string_by_size (2);
  version_ = decoder.get_uint16_be ();
  attributes_ = decoder.get_uint32_be ();
  decoder.skip (8);             // lastMountedVersion, journalInfoBlock
  creation_time_ = decoder.get_hfs_datetime ();
  last_modification_time_ = decoder.get_hfs_datetime ();
  last_backup_time_ = decoder.get_hfs_datetime ();;
  last_check_time_ = decoder.get_hfs_datetime ();
  file_count_ = decoder.get_uint32_be ();
  folder_count_ = decoder.get_uint32_be ();
  block_size_ = decoder.get_uint32_be ();
  total_blocks_ = decoder.get_uint32_be ();
  free_blocks_ = decoder.get_uint32_be ();
  decoder.skip (16);            // nextAllocation...nextCatalogID
  mount_count_ = decoder.get_uint32_be ();
  decoder.skip (32);            // encodingsBitmap..finderInfo[5]
  volume_uuid_ = decoder.get_bytearray_by_size (8).to_hexstring ();

  // derived information
  set_size (total_blocks_ * block_size_);
  set_fs_type ((version_ == 4) ? "HFS+" : "HFSX");
  set_name (get_fs_type () + " (uuid: " + volume_uuid_ + ')');
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief get metadata
//! \return metadata
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const mobius::metadata
filesystem_impl_hfs::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_uuid",
      "volume UUID",
      "std::string",
      get_volume_uuid ()
    },
    {
      "volume_name",
      "volume name",
      "std::string",
      get_volume_name ()
    },
    {
      "signature",
      "file system signature",
      "std::string",
      get_signature ()
    },
    {
      "version",
      "file system version",
      "std::uint16_t",
      std::to_string (get_version ())
    },
    {
      "attributes",
      "attributes",
      "std::uint32_t",
      std::to_string (get_attributes ())
    },
    {
      "creation_time",
      "file system creation date/time",
      "mobius::datetime::datetime",
      to_string (get_creation_time ())
    },
    {
      "last_modification_time",
      "last modification date/time",
      "mobius::datetime::datetime",
      to_string (get_last_modification_time ())
    },
    {
      "last_backup_time",
      "last backup date/time",
      "mobius::datetime::datetime",
      to_string (get_last_backup_time ())
    },
    {
      "last_check_time",
      "last check date/time",
      "mobius::datetime::datetime",
      to_string (get_last_check_time ())
    },
    {
      "file_count",
      "total number of files",
      "std::uint32_t",
      std::to_string (get_file_count ())
    },
    {
      "folder_count",
      "total number of folders",
      "std::uint32_t",
      std::to_string (get_folder_count ())
    },
    {
      "block_size",
      "block size",
      "std::uint32_t",
      std::to_string (get_block_size ()) + " bytes"
    },
    {
      "total_blocks",
      "number of allocation blocks",
      "std::uint32_t",
      std::to_string (get_total_blocks ())
    },
    {
      "free_blocks",
      "number of unused allocation blocks",
      "std::uint32_t",
      std::to_string (get_free_blocks ())
    },
    {
      "mount_count",
      "number of times the file system was mounted",
      "std::uint32_t",
      std::to_string (get_mount_count ())
    },
  };
}

} // namespace filesystem
} // namespace mobius
