// Copyright 2018 The Crashpad Authors. 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.

#include "snapshot/minidump/system_snapshot_minidump.h"

#include "snapshot/minidump/minidump_string_reader.h"

namespace crashpad {
namespace internal {

SystemSnapshotMinidump::SystemSnapshotMinidump()
    : SystemSnapshot(),
      minidump_system_info_(),
      initialized_() {
}

SystemSnapshotMinidump::~SystemSnapshotMinidump() {
}

bool SystemSnapshotMinidump::Initialize(FileReaderInterface* file_reader,
                                        RVA minidump_system_info_rva) {
  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
  if (!file_reader->SeekSet(minidump_system_info_rva)) {
    return false;
  }

  if (!file_reader->ReadExactly(&minidump_system_info_,
                                sizeof(minidump_system_info_))) {
    return false;
  }

  if (!ReadMinidumpUTF8String(file_reader, minidump_system_info_.CSDVersionRva,
                              &minidump_build_name_)) {
    return false;
  }

  INITIALIZATION_STATE_SET_VALID(initialized_);
  return true;
}

CPUArchitecture SystemSnapshotMinidump::GetCPUArchitecture() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  switch (minidump_system_info_.ProcessorArchitecture) {
  case kMinidumpCPUArchitectureAMD64:
    return kCPUArchitectureX86_64;
  case kMinidumpCPUArchitectureX86:
  case kMinidumpCPUArchitectureX86Win64:
    return kCPUArchitectureX86;
  case kMinidumpCPUArchitectureARM:
  case kMinidumpCPUArchitectureARM32Win64:
    return kCPUArchitectureARM;
  case kMinidumpCPUArchitectureARM64:
  case kMinidumpCPUArchitectureARM64Breakpad:
    return kCPUArchitectureARM64;
  case kMinidumpCPUArchitectureMIPS:
    return kCPUArchitectureMIPSEL;
  // No word on how MIPS64 is signalled

  default:
    return CPUArchitecture::kCPUArchitectureUnknown;
  }
}

uint32_t SystemSnapshotMinidump::CPURevision() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  return minidump_system_info_.ProcessorRevision;
}

uint8_t SystemSnapshotMinidump::CPUCount() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  return minidump_system_info_.NumberOfProcessors;
}

std::string SystemSnapshotMinidump::CPUVendor() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  if (GetCPUArchitecture() == kCPUArchitectureX86) {
    const char* ptr =
      reinterpret_cast<const char*>(minidump_system_info_.Cpu.X86CpuInfo.
                                    VendorId);
    return std::string(ptr, ptr + (3 * sizeof(uint32_t)));
  } else {
    return std::string();
  }
}

void SystemSnapshotMinidump::CPUFrequency(uint64_t* current_hz,
                                          uint64_t* max_hz) const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
}

uint32_t SystemSnapshotMinidump::CPUX86Signature() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return 0;
}

uint64_t SystemSnapshotMinidump::CPUX86Features() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return 0;
}

uint64_t SystemSnapshotMinidump::CPUX86ExtendedFeatures() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return 0;
}

uint32_t SystemSnapshotMinidump::CPUX86Leaf7Features() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return 0;
}

bool SystemSnapshotMinidump::CPUX86SupportsDAZ() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return false;
}

SystemSnapshot::OperatingSystem
    SystemSnapshotMinidump::GetOperatingSystem() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);

  switch (minidump_system_info_.PlatformId) {
  case kMinidumpOSMacOSX:
    return OperatingSystem::kOperatingSystemMacOSX;
  case kMinidumpOSWin32s:
  case kMinidumpOSWin32Windows:
  case kMinidumpOSWin32NT:
    return OperatingSystem::kOperatingSystemWindows;
  case kMinidumpOSLinux:
    return OperatingSystem::kOperatingSystemLinux;
  case kMinidumpOSAndroid:
    return OperatingSystem::kOperatingSystemAndroid;
  case kMinidumpOSFuchsia:
    return OperatingSystem::kOperatingSystemFuchsia;
  default:
    return OperatingSystem::kOperatingSystemUnknown;
  }
}

bool SystemSnapshotMinidump::OSServer() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  return minidump_system_info_.ProductType == kMinidumpOSTypeServer;
}

void SystemSnapshotMinidump::OSVersion(int* major,
                                       int* minor,
                                       int* bugfix,
                                       std::string* build) const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  *major = minidump_system_info_.MajorVersion;
  *minor = minidump_system_info_.MinorVersion;
  *bugfix = minidump_system_info_.BuildNumber;
  *build = minidump_build_name_;
}

std::string SystemSnapshotMinidump::OSVersionFull() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return std::string();
}

std::string SystemSnapshotMinidump::MachineDescription() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return std::string();
}

bool SystemSnapshotMinidump::NXEnabled() const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
  return false;
}

void SystemSnapshotMinidump::TimeZone(DaylightSavingTimeStatus* dst_status,
                                      int* standard_offset_seconds,
                                      int* daylight_offset_seconds,
                                      std::string* standard_name,
                                      std::string* daylight_name) const {
  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  NOTREACHED();  // https://crashpad.chromium.org/bug/10
}

}  // namespace internal
}  // namespace crashpad
