/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/base/file.h"

#include <io.h>
#include "webrtc/base/win32.h"

#include <limits>  // NOLINT: win32.h should be considered a system header

#include "webrtc/base/checks.h"

namespace rtc {

size_t File::Write(const uint8_t* data, size_t length) {
  RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
  size_t total_written = 0;
  do {
    DWORD written;
    if (!::WriteFile(file_, data + total_written,
                     static_cast<DWORD>(length - total_written), &written,
                     nullptr)) {
      break;
    }
    total_written += written;
  } while (total_written < length);
  return total_written;
}

size_t File::Read(uint8_t* buffer, size_t length) {
  RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
  size_t total_read = 0;
  do {
    DWORD read;
    if (!::ReadFile(file_, buffer + total_read,
                    static_cast<DWORD>(length - total_read), &read, nullptr)) {
      break;
    }
    total_read += read;
  } while (total_read < length);
  return total_read;
}

size_t File::WriteAt(const uint8_t* data, size_t length, size_t offset) {
  RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
  size_t total_written = 0;
  do {
    DWORD written;

    LARGE_INTEGER offset_li;
    offset_li.QuadPart = offset + total_written;

    OVERLAPPED overlapped = {0};
    overlapped.Offset = offset_li.LowPart;
    overlapped.OffsetHigh = offset_li.HighPart;

    if (!::WriteFile(file_, data + total_written,
                     static_cast<DWORD>(length - total_written), &written,
                     &overlapped)) {
      break;
    }

    total_written += written;
  } while (total_written < length);
  return total_written;
}

size_t File::ReadAt(uint8_t* buffer, size_t length, size_t offset) {
  RTC_DCHECK_LT(length, std::numeric_limits<DWORD>::max());
  size_t total_read = 0;
  do {
    DWORD read;

    LARGE_INTEGER offset_li;
    offset_li.QuadPart = offset + total_read;

    OVERLAPPED overlapped = {0};
    overlapped.Offset = offset_li.LowPart;
    overlapped.OffsetHigh = offset_li.HighPart;

    if (!::ReadFile(file_, buffer + total_read,
                    static_cast<DWORD>(length - total_read), &read,
                    &overlapped)) {
      break;
    }

    total_read += read;
  } while (total_read < length);
  return total_read;
}

bool File::Seek(size_t offset) {
  LARGE_INTEGER distance;
  distance.QuadPart = offset;
  return SetFilePointerEx(file_, distance, nullptr, FILE_BEGIN) != 0;
}

bool File::Close() {
  if (file_ == kInvalidPlatformFileValue)
    return false;
  bool ret = CloseHandle(file_) != 0;
  file_ = kInvalidPlatformFileValue;
  return ret;
}

}  // namespace rtc
