<commit_before>// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "shell/browser/electron_permission_manager.h"

#include <memory>
#include <utility>
#include <vector>

#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "shell/browser/electron_browser_client.h"
#include "shell/browser/electron_browser_main_parts.h"
#include "shell/browser/web_contents_preferences.h"

namespace electron {

namespace {

bool WebContentsDestroyed(int process_id) {
  content::WebContents* web_contents =
      static_cast<ElectronBrowserClient*>(ElectronBrowserClient::Get())
          ->GetWebContentsFromProcessID(process_id);
  if (!web_contents)
    return true;
  return web_contents->IsBeingDestroyed();
}

void PermissionRequestResponseCallbackWrapper(
    ElectronPermissionManager::StatusCallback callback,
    const std::vector<blink::mojom::PermissionStatus>& vector) {
  std::move(callback).Run(vector[0]);
}

}  // namespace

class ElectronPermissionManager::PendingRequest {
 public:
  PendingRequest(content::RenderFrameHost* render_frame_host,
                 const std::vector<content::PermissionType>& permissions,
                 StatusesCallback callback)
      : render_process_id_(render_frame_host->GetProcess()->GetID()),
        callback_(std::move(callback)),
        permissions_(permissions),
        results_(permissions.size(), blink::mojom::PermissionStatus::DENIED),
        remaining_results_(permissions.size()) {}

  void SetPermissionStatus(int permission_id,
                           blink::mojom::PermissionStatus status) {
    DCHECK(!IsComplete());

    if (status == blink::mojom::PermissionStatus::GRANTED) {
      const auto permission = permissions_[permission_id];
      if (permission == content::PermissionType::MIDI_SYSEX) {
        content::ChildProcessSecurityPolicy::GetInstance()
            ->GrantSendMidiSysExMessage(render_process_id_);
      } else if (permission == content::PermissionType::GEOLOCATION) {
        ElectronBrowserMainParts::Get()
            ->GetGeolocationControl()
            ->UserDidOptIntoLocationServices();
      }
    }

    results_[permission_id] = status;
    --remaining_results_;
  }

  int render_process_id() const { return render_process_id_; }

  bool IsComplete() const { return remaining_results_ == 0; }

  void RunCallback() {
    if (!callback_.is_null()) {
      std::move(callback_).Run(results_);
    }
  }

 private:
  int render_process_id_;
  StatusesCallback callback_;
  std::vector<content::PermissionType> permissions_;
  std::vector<blink::mojom::PermissionStatus> results_;
  size_t remaining_results_;
};

ElectronPermissionManager::ElectronPermissionManager() = default;

ElectronPermissionManager::~ElectronPermissionManager() = default;

void ElectronPermissionManager::SetPermissionRequestHandler(
    const RequestHandler& handler) {
  if (handler.is_null() && !pending_requests_.IsEmpty()) {
    for (PendingRequestsMap::iterator iter(&pending_requests_); !iter.IsAtEnd();
         iter.Advance()) {
      auto* request = iter.GetCurrentValue();
      if (!WebContentsDestroyed(request->render_process_id()))
        request->RunCallback();
    }
    pending_requests_.Clear();
  }
  request_handler_ = handler;
}

void ElectronPermissionManager::SetPermissionCheckHandler(
    const CheckHandler& handler) {
  check_handler_ = handler;
}

void ElectronPermissionManager::RequestPermission(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    StatusCallback response_callback) {
  RequestPermissionWithDetails(permission, render_frame_host, requesting_origin,
                               user_gesture, nullptr,
                               std::move(response_callback));
}

void ElectronPermissionManager::RequestPermissionWithDetails(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    const base::DictionaryValue* details,
    StatusCallback response_callback) {
  RequestPermissionsWithDetails(
      std::vector<content::PermissionType>(1, permission), render_frame_host,
      requesting_origin, user_gesture, details,
      base::BindOnce(PermissionRequestResponseCallbackWrapper,
                     std::move(response_callback)));
}

void ElectronPermissionManager::RequestPermissions(
    const std::vector<content::PermissionType>& permissions,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    StatusesCallback response_callback) {
  RequestPermissionsWithDetails(permissions, render_frame_host,
                                requesting_origin, user_gesture, nullptr,
                                std::move(response_callback));
}

void ElectronPermissionManager::RequestPermissionsWithDetails(
    const std::vector<content::PermissionType>& permissions,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    const base::DictionaryValue* details,
    StatusesCallback response_callback) {
  if (permissions.empty()) {
    std::move(response_callback).Run({});
    return;
  }

  if (request_handler_.is_null()) {
    std::vector<blink::mojom::PermissionStatus> statuses;
    for (auto permission : permissions) {
      if (permission == content::PermissionType::MIDI_SYSEX) {
        content::ChildProcessSecurityPolicy::GetInstance()
            ->GrantSendMidiSysExMessage(
                render_frame_host->GetProcess()->GetID());
      } else if (permission == content::PermissionType::GEOLOCATION) {
        ElectronBrowserMainParts::Get()
            ->GetGeolocationControl()
            ->UserDidOptIntoLocationServices();
      }
      statuses.push_back(blink::mojom::PermissionStatus::GRANTED);
    }
    std::move(response_callback).Run(statuses);
    return;
  }

  auto* web_contents =
      content::WebContents::FromRenderFrameHost(render_frame_host);
  int request_id = pending_requests_.Add(std::make_unique<PendingRequest>(
      render_frame_host, permissions, std::move(response_callback)));

  for (size_t i = 0; i < permissions.size(); ++i) {
    auto permission = permissions[i];
    const auto callback =
        base::BindRepeating(&ElectronPermissionManager::OnPermissionResponse,
                            base::Unretained(this), request_id, i);
    auto mutable_details =
        details == nullptr ? base::DictionaryValue() : details->Clone();
    mutable_details.SetStringKey(
        "requestingUrl", render_frame_host->GetLastCommittedURL().spec());
    mutable_details.SetBoolKey("isMainFrame",
                               render_frame_host->GetParent() == nullptr);
    request_handler_.Run(web_contents, permission, callback, mutable_details);
  }
}

void ElectronPermissionManager::OnPermissionResponse(
    int request_id,
    int permission_id,
    blink::mojom::PermissionStatus status) {
  auto* pending_request = pending_requests_.Lookup(request_id);
  if (!pending_request)
    return;

  pending_request->SetPermissionStatus(permission_id, status);
  if (pending_request->IsComplete()) {
    pending_request->RunCallback();
    pending_requests_.Remove(request_id);
  }
}

void ElectronPermissionManager::ResetPermission(
    content::PermissionType permission,
    const GURL& requesting_origin,
    const GURL& embedding_origin) {}

blink::mojom::PermissionStatus ElectronPermissionManager::GetPermissionStatus(
    content::PermissionType permission,
    const GURL& requesting_origin,
    const GURL& embedding_origin) {
  base::DictionaryValue details;
  details.SetString("embeddingOrigin", embedding_origin.spec());
  bool granted = CheckPermissionWithDetails(permission, nullptr,
                                            requesting_origin, &details);
  return granted ? blink::mojom::PermissionStatus::GRANTED
                 : blink::mojom::PermissionStatus::DENIED;
}

ElectronPermissionManager::SubscriptionId
ElectronPermissionManager::SubscribePermissionStatusChange(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) {
  return SubscriptionId(-1);
}

void ElectronPermissionManager::UnsubscribePermissionStatusChange(
    SubscriptionId id) {}

bool ElectronPermissionManager::CheckPermissionWithDetails(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    const base::DictionaryValue* details) const {
  if (check_handler_.is_null()) {
    return true;
  }
  auto* web_contents =
      render_frame_host
          ? content::WebContents::FromRenderFrameHost(render_frame_host)
          : nullptr;
  auto mutable_details =
      details == nullptr ? base::DictionaryValue() : details->Clone();
  if (render_frame_host) {
    mutable_details.SetStringKey(
        "requestingUrl", render_frame_host->GetLastCommittedURL().spec());
  }
  mutable_details.SetBoolKey(
      "isMainFrame",
      render_frame_host && render_frame_host->GetParent() == nullptr);
  switch (permission) {
    case content::PermissionType::AUDIO_CAPTURE:
      mutable_details.SetStringKey("mediaType", "audio");
      break;
    case content::PermissionType::VIDEO_CAPTURE:
      mutable_details.SetStringKey("mediaType", "video");
      break;
    default:
      break;
  }
  return check_handler_.Run(web_contents, permission, requesting_origin,
                            mutable_details);
}

blink::mojom::PermissionStatus
ElectronPermissionManager::GetPermissionStatusForFrame(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin) {
  base::DictionaryValue details;
  bool granted = CheckPermissionWithDetails(permission, render_frame_host,
                                            requesting_origin, &details);
  return granted ? blink::mojom::PermissionStatus::GRANTED
                 : blink::mojom::PermissionStatus::DENIED;
}

}  // namespace electron
<commit_msg>refactor: use rfh instead of process id in permission manager (#28791)<commit_after>// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "shell/browser/electron_permission_manager.h"

#include <memory>
#include <utility>
#include <vector>

#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "shell/browser/electron_browser_client.h"
#include "shell/browser/electron_browser_main_parts.h"
#include "shell/browser/web_contents_preferences.h"

namespace electron {

namespace {

bool WebContentsDestroyed(content::RenderFrameHost* rfh) {
  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(rfh);
  if (!web_contents)
    return true;
  return web_contents->IsBeingDestroyed();
}

void PermissionRequestResponseCallbackWrapper(
    ElectronPermissionManager::StatusCallback callback,
    const std::vector<blink::mojom::PermissionStatus>& vector) {
  std::move(callback).Run(vector[0]);
}

}  // namespace

class ElectronPermissionManager::PendingRequest {
 public:
  PendingRequest(content::RenderFrameHost* render_frame_host,
                 const std::vector<content::PermissionType>& permissions,
                 StatusesCallback callback)
      : render_process_id_(render_frame_host->GetProcess()->GetID()),
        render_frame_id_(render_frame_host->GetGlobalFrameRoutingId()),
        callback_(std::move(callback)),
        permissions_(permissions),
        results_(permissions.size(), blink::mojom::PermissionStatus::DENIED),
        remaining_results_(permissions.size()) {}

  void SetPermissionStatus(int permission_id,
                           blink::mojom::PermissionStatus status) {
    DCHECK(!IsComplete());

    if (status == blink::mojom::PermissionStatus::GRANTED) {
      const auto permission = permissions_[permission_id];
      if (permission == content::PermissionType::MIDI_SYSEX) {
        content::ChildProcessSecurityPolicy::GetInstance()
            ->GrantSendMidiSysExMessage(render_process_id_);
      } else if (permission == content::PermissionType::GEOLOCATION) {
        ElectronBrowserMainParts::Get()
            ->GetGeolocationControl()
            ->UserDidOptIntoLocationServices();
      }
    }

    results_[permission_id] = status;
    --remaining_results_;
  }

  content::RenderFrameHost* GetRenderFrameHost() {
    return content::RenderFrameHost::FromID(render_frame_id_);
  }

  bool IsComplete() const { return remaining_results_ == 0; }

  void RunCallback() {
    if (!callback_.is_null()) {
      std::move(callback_).Run(results_);
    }
  }

 private:
  int render_process_id_;
  content::GlobalFrameRoutingId render_frame_id_;
  StatusesCallback callback_;
  std::vector<content::PermissionType> permissions_;
  std::vector<blink::mojom::PermissionStatus> results_;
  size_t remaining_results_;
};

ElectronPermissionManager::ElectronPermissionManager() = default;

ElectronPermissionManager::~ElectronPermissionManager() = default;

void ElectronPermissionManager::SetPermissionRequestHandler(
    const RequestHandler& handler) {
  if (handler.is_null() && !pending_requests_.IsEmpty()) {
    for (PendingRequestsMap::iterator iter(&pending_requests_); !iter.IsAtEnd();
         iter.Advance()) {
      auto* request = iter.GetCurrentValue();
      if (!WebContentsDestroyed(request->GetRenderFrameHost()))
        request->RunCallback();
    }
    pending_requests_.Clear();
  }
  request_handler_ = handler;
}

void ElectronPermissionManager::SetPermissionCheckHandler(
    const CheckHandler& handler) {
  check_handler_ = handler;
}

void ElectronPermissionManager::RequestPermission(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    StatusCallback response_callback) {
  RequestPermissionWithDetails(permission, render_frame_host, requesting_origin,
                               user_gesture, nullptr,
                               std::move(response_callback));
}

void ElectronPermissionManager::RequestPermissionWithDetails(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    const base::DictionaryValue* details,
    StatusCallback response_callback) {
  RequestPermissionsWithDetails(
      std::vector<content::PermissionType>(1, permission), render_frame_host,
      requesting_origin, user_gesture, details,
      base::BindOnce(PermissionRequestResponseCallbackWrapper,
                     std::move(response_callback)));
}

void ElectronPermissionManager::RequestPermissions(
    const std::vector<content::PermissionType>& permissions,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    StatusesCallback response_callback) {
  RequestPermissionsWithDetails(permissions, render_frame_host,
                                requesting_origin, user_gesture, nullptr,
                                std::move(response_callback));
}

void ElectronPermissionManager::RequestPermissionsWithDetails(
    const std::vector<content::PermissionType>& permissions,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    bool user_gesture,
    const base::DictionaryValue* details,
    StatusesCallback response_callback) {
  if (permissions.empty()) {
    std::move(response_callback).Run({});
    return;
  }

  if (request_handler_.is_null()) {
    std::vector<blink::mojom::PermissionStatus> statuses;
    for (auto permission : permissions) {
      if (permission == content::PermissionType::MIDI_SYSEX) {
        content::ChildProcessSecurityPolicy::GetInstance()
            ->GrantSendMidiSysExMessage(
                render_frame_host->GetProcess()->GetID());
      } else if (permission == content::PermissionType::GEOLOCATION) {
        ElectronBrowserMainParts::Get()
            ->GetGeolocationControl()
            ->UserDidOptIntoLocationServices();
      }
      statuses.push_back(blink::mojom::PermissionStatus::GRANTED);
    }
    std::move(response_callback).Run(statuses);
    return;
  }

  auto* web_contents =
      content::WebContents::FromRenderFrameHost(render_frame_host);
  int request_id = pending_requests_.Add(std::make_unique<PendingRequest>(
      render_frame_host, permissions, std::move(response_callback)));

  for (size_t i = 0; i < permissions.size(); ++i) {
    auto permission = permissions[i];
    const auto callback =
        base::BindRepeating(&ElectronPermissionManager::OnPermissionResponse,
                            base::Unretained(this), request_id, i);
    auto mutable_details =
        details == nullptr ? base::DictionaryValue() : details->Clone();
    mutable_details.SetStringKey(
        "requestingUrl", render_frame_host->GetLastCommittedURL().spec());
    mutable_details.SetBoolKey("isMainFrame",
                               render_frame_host->GetParent() == nullptr);
    request_handler_.Run(web_contents, permission, callback, mutable_details);
  }
}

void ElectronPermissionManager::OnPermissionResponse(
    int request_id,
    int permission_id,
    blink::mojom::PermissionStatus status) {
  auto* pending_request = pending_requests_.Lookup(request_id);
  if (!pending_request)
    return;

  pending_request->SetPermissionStatus(permission_id, status);
  if (pending_request->IsComplete()) {
    pending_request->RunCallback();
    pending_requests_.Remove(request_id);
  }
}

void ElectronPermissionManager::ResetPermission(
    content::PermissionType permission,
    const GURL& requesting_origin,
    const GURL& embedding_origin) {}

blink::mojom::PermissionStatus ElectronPermissionManager::GetPermissionStatus(
    content::PermissionType permission,
    const GURL& requesting_origin,
    const GURL& embedding_origin) {
  base::DictionaryValue details;
  details.SetString("embeddingOrigin", embedding_origin.spec());
  bool granted = CheckPermissionWithDetails(permission, nullptr,
                                            requesting_origin, &details);
  return granted ? blink::mojom::PermissionStatus::GRANTED
                 : blink::mojom::PermissionStatus::DENIED;
}

ElectronPermissionManager::SubscriptionId
ElectronPermissionManager::SubscribePermissionStatusChange(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) {
  return SubscriptionId(-1);
}

void ElectronPermissionManager::UnsubscribePermissionStatusChange(
    SubscriptionId id) {}

bool ElectronPermissionManager::CheckPermissionWithDetails(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin,
    const base::DictionaryValue* details) const {
  if (check_handler_.is_null()) {
    return true;
  }
  auto* web_contents =
      render_frame_host
          ? content::WebContents::FromRenderFrameHost(render_frame_host)
          : nullptr;
  auto mutable_details =
      details == nullptr ? base::DictionaryValue() : details->Clone();
  if (render_frame_host) {
    mutable_details.SetStringKey(
        "requestingUrl", render_frame_host->GetLastCommittedURL().spec());
  }
  mutable_details.SetBoolKey(
      "isMainFrame",
      render_frame_host && render_frame_host->GetParent() == nullptr);
  switch (permission) {
    case content::PermissionType::AUDIO_CAPTURE:
      mutable_details.SetStringKey("mediaType", "audio");
      break;
    case content::PermissionType::VIDEO_CAPTURE:
      mutable_details.SetStringKey("mediaType", "video");
      break;
    default:
      break;
  }
  return check_handler_.Run(web_contents, permission, requesting_origin,
                            mutable_details);
}

blink::mojom::PermissionStatus
ElectronPermissionManager::GetPermissionStatusForFrame(
    content::PermissionType permission,
    content::RenderFrameHost* render_frame_host,
    const GURL& requesting_origin) {
  base::DictionaryValue details;
  bool granted = CheckPermissionWithDetails(permission, render_frame_host,
                                            requesting_origin, &details);
  return granted ? blink::mojom::PermissionStatus::GRANTED
                 : blink::mojom::PermissionStatus::DENIED;
}

}  // namespace electron
<|endoftext|>


<commit_before>#include "fs.hpp"
#include "ui.hpp"

#include <citrus/core.hpp>
#include <citrus/hid.hpp>

#include <sys/dirent.h>
#include <sys/errno.h>
#include <sys/unistd.h>
#include <string.h>

#include <cstdio>
#include <cstdlib>
#include <algorithm>

#include <3ds.h>

using namespace ctr;

#define CTRX_BUFSIZ (4 * 1024 * 1024)

struct fsAlphabetizeFoldersFiles {
    inline bool operator()(FileInfoEx a, FileInfoEx b) {
        if(a.isDirectory == b.isDirectory)
            return strcasecmp(a.name.c_str(), b.name.c_str()) < 0;
        else return a.isDirectory;
    }
};

bool fsShowProgress(const std::string operationStr, const std::string pathStr, u64 pos, u64 totalSize) {
    static u32 prevProgress = -1;
    u32 progress = (u32) ((pos * 100) / totalSize);
    if(prevProgress != progress) {
        prevProgress = progress;
        uiDisplayProgress(gpu::SCREEN_TOP, operationStr, uiTruncateString(pathStr, 36, 0) + "\nPress B to cancel.", true, progress);
    }

    hid::poll();
    return !hid::pressed(hid::BUTTON_B);
}

u64 fsGetFreeSpace() {
    FS_ArchiveResource resource;
    Result res = FSUSER_GetSdmcArchiveResource(&resource);
    return (res != 0) ? 0 : (u64) resource.clusterSize * (u64) resource.freeClusters;
}

bool fsExists(const std::string path) {
    FILE* fd = fopen(path.c_str(), "r");
    if(fd) {
        fclose(fd);
        return true;
    }

    return fsIsDirectory(path);
}

bool fsIsDirectory(const std::string path) {
    DIR* dir = opendir(path.c_str());
    if(dir) {
        closedir(dir);
        return true;
    }

    return false;
}

std::string fsGetFileName(const std::string path) {
    std::string::size_type slashPos = path.rfind('/');
    if(slashPos == std::string::npos) {
        return path;
    }

    return path.substr(slashPos + 1);
}

std::string fsGetExtension(const std::string path) {
    std::string::size_type dotPos = path.rfind('.');
    if(dotPos == std::string::npos) {
        return "";
    }

    return path.substr(dotPos + 1);
}

bool fsHasExtension(const std::string path, const std::string extension) {
    if(extension.empty()) {
        return true;
    }

    const std::string ext = fsGetExtension(path);
    return strcasecmp(ext.c_str(), extension.c_str()) == 0;
}

bool fsHasExtensions(const std::string path, const std::vector<std::string> extensions) {
    if(extensions.empty()) {
        return true;
    }

    const std::string ext = fsGetExtension(path);
    for(std::vector<std::string>::const_iterator it = extensions.begin(); it != extensions.end(); it++) {
        std::string extension = *it;
        if(strcasecmp(ext.c_str(), extension.c_str()) == 0) {
            return true;
        }
    }

    return false;
}

u32 fsGetFileSize(const std::string path) {
    struct stat st;
    stat(path.c_str(), &st);
    return (u32) st.st_size;
}

bool fsProvideData(const std::string path, u32 offset, u32 buffSize, std::function<bool(u32 &offset)> onLoop, std::function<bool(u8* data)> onUpdate) {
    if((onLoop == NULL) || (onUpdate == NULL)) {
        errno = ENOTSUP;
        return false;
    }
    if(!fsExists(path)) {
        errno = ENOENT;
        return false;
    }

    FILE* fp = fopen(path.c_str(), "rb");
    u8* buffer = (u8*) calloc(buffSize, 1);
    u8* bufferEnd = buffer + buffSize;

    u32 fileSize  = fsGetFileSize(path);
    u32 offsetPrev = (u32) -1;

    bool result = false;

    if((fp == NULL) || (buffer == NULL)) {
        if(fp != NULL) fclose(fp);
        if(buffer != NULL) free(buffer);
        return false;
    }

    while(core::running()) {
        if((offset != offsetPrev) && (offset <= fileSize)) {
            if(offset < offsetPrev) {
                u32 dataEnd = offset + buffSize;
                u32 overlap = (dataEnd > offsetPrev) ? dataEnd - offsetPrev : 0;
                memmove(bufferEnd - overlap, buffer, overlap);
                fseek(fp, offset, SEEK_SET);
                fread(buffer, 1, buffSize - overlap, fp);
            } else {
                u32 dataEnd = offset + buffSize;
                u32 dataEndPrev = offsetPrev + buffSize;
                u32 overlap = (dataEndPrev > offset) ? dataEndPrev - offset : 0;
                memmove(buffer, bufferEnd - overlap, overlap);
                if(dataEnd > fileSize) {
                    memset(buffer + overlap, 0x00, buffSize - overlap);
                }
                fseek(fp, offset + overlap, SEEK_SET);
                fread(buffer + overlap, 1, buffSize - overlap, fp);
            }
            offsetPrev = offset;
            if(onUpdate(buffer)) {
                result = true;
            }
        } else if(offset > fileSize) {
            offset = fileSize;
        } else if(onLoop(offset)) {
            result = true;
        }

        if(result) break;
    }

    if(fp != NULL) fclose(fp);
    if(buffer != NULL) free(buffer);

    return result;
}

bool fsPathDelete(const std::string path) {
    if(fsIsDirectory(path)) {
        std::vector<FileInfo> contents = fsGetDirectoryContents(path);
        for (std::vector<FileInfo>::iterator it = contents.begin(); it != contents.end(); it++)
            if (!fsPathDelete((*it).path)) return false;
        return (rmdir(path.c_str()) == 0);
    } else return (remove(path.c_str()) == 0);
}

bool fsPathCopy(const std::string path, const std::string dest, bool showProgress) {
    if(fsExists(dest)) {
        errno = EEXIST;
        return false;
    }
    if(showProgress) fsShowProgress("Copying", path, 0, 1);
    if(fsIsDirectory(path)) {
        if(dest.find(path + "/") != std::string::npos) {
            errno = ENOTSUP;
            return false;
        }
        if(mkdir(dest.c_str(), 0777) != 0) return false;
        if(showProgress) fsShowProgress("Copying", path, 1, 2);
        std::vector<FileInfo> contents = fsGetDirectoryContents(path);
        for (std::vector<FileInfo>::iterator it = contents.begin(); it != contents.end(); it++)
            if (!fsPathCopy((*it).path, dest + "/" + (*it).name, showProgress)) return false;
        return true;
    } else {
        bool ret = false;
        u64 total = fsGetFileSize(path);
        size_t l_bufsiz = (total < CTRX_BUFSIZ) ? total : CTRX_BUFSIZ;
        u8* buffer = (u8*) malloc( l_bufsiz );
        FILE* fp = fopen(path.c_str(), "rb");
        FILE* fd = fopen(dest.c_str(), "wb");
        if ((fp != NULL) && (fd != NULL) && (buffer != NULL)) {
            u64 pos = 0;
            size_t size;
            while ((size = fread(buffer, 1, l_bufsiz, fp)) > 0) {
                pos += fwrite(buffer, 1, size, fd);
                if(showProgress && !fsShowProgress("Copying", path, pos, total)) {
                    errno = ECANCELED;
                    break;
                }
            }
            ret = (pos == total);
        }
        if(buffer != NULL) free(buffer);
        if(fp != NULL) fclose(fp);
        if(fd != NULL) fclose(fd);
        return ret;
    }
}

bool fsPathRename(const std::string path, const std::string dest) {
    if(dest.find(path + "/") != std::string::npos) {
        errno = ENOTSUP;
        return false;
    }
    if(fsExists(dest)) {
        errno = EEXIST;
        return false;
    }
    return (rename(path.c_str(), dest.c_str()) == 0);
}

bool fsCreateDir(const std::string path) {
    if(fsExists(path)) {
        errno = EEXIST;
        return false;
    }
    return (mkdir(path.c_str(), 0777) == 0);
}

bool fsCreateDummyFile(const std::string path, u64 size, u16 content, bool showProgress) {
    if(fsExists(path)) {
        errno = EEXIST;
        return false;
    }
    if(size < CTRX_BUFSIZ) showProgress = false;
    if(showProgress) fsShowProgress("Generating", path, 0, 1);
    bool ret = false;
    size_t l_bufsiz = (size < CTRX_BUFSIZ) ? size : CTRX_BUFSIZ;
    u8* buffer = (u8*) malloc( l_bufsiz );
    FILE* fp = fopen(path.c_str(), "wb");
    if((fp != NULL) && (buffer != NULL)) {
        if(content & 0xFF00) {
            u8 byte = content & 0xFF;
            u8 inc = (content >> 8) & 0xFF;
            for(u64 count = 0; count < l_bufsiz; count++, byte += inc)
                buffer[count] = byte;
        } else memset(buffer, content, l_bufsiz);
        u64 pos = 0;
        for(u64 count = 0; count < size; count += l_bufsiz) {
            if(size - count < l_bufsiz) l_bufsiz = size - count;
            pos += fwrite(buffer, 1, l_bufsiz, fp);
            if(showProgress && !fsShowProgress("Generating", path, pos, size)) {
                errno = ECANCELED;
                break;
            }
        }
        ret = (pos == size);
    }
    if(buffer != NULL) free(buffer);
    if(fp != NULL) fclose(fp);
    return ret;
}

std::vector<FileInfo> fsGetDirectoryContents(const std::string directory) {
    std::vector<FileInfo> result;
    bool hasSlash = directory.size() != 0 && directory[directory.size() - 1] == '/';
    const std::string dirWithSlash = hasSlash ? directory : directory + "/";

    DIR* dir = opendir(dirWithSlash.c_str());
    if(dir == NULL) {
        return result;
    }

    while(true) {
        struct dirent* ent = readdir(dir);
        if(ent == NULL) {
            break;
        }
        result.push_back({dirWithSlash + std::string(ent->d_name), std::string(ent->d_name)});
    }

    closedir(dir);
    return result;
}

std::vector<FileInfoEx> fsGetDirectoryContentsEx(const std::string directory) {
    std::vector<FileInfoEx> result;
    bool hasSlash = directory.size() != 0 && directory[directory.size() - 1] == '/';
    const std::string dirWithSlash = hasSlash ? directory : directory + "/";

    DIR* dir = opendir(dirWithSlash.c_str());
    if(dir == NULL) {
        return result;
    }

    while(true) {
        struct dirent* ent = readdir(dir);
        if(ent == NULL) {
            break;
        }
        const std::string name = std::string(ent->d_name);
        if((name.compare(".") != 0) && (name.compare("..") != 0)) {
            const std::string path = dirWithSlash + std::string(ent->d_name);
            bool isDirectory = fsIsDirectory(path);
            result.push_back({path, std::string(ent->d_name), isDirectory});
        }
    }

    closedir(dir);
    std::sort(result.begin(), result.end(), fsAlphabetizeFoldersFiles());
    return result;
}
<commit_msg>Actually make aborting file copy possible again<commit_after>#include "fs.hpp"
#include "ui.hpp"

#include <citrus/core.hpp>
#include <citrus/hid.hpp>

#include <sys/dirent.h>
#include <sys/errno.h>
#include <sys/unistd.h>
#include <string.h>

#include <cstdio>
#include <cstdlib>
#include <algorithm>

#include <3ds.h>

using namespace ctr;

#define CTRX_BUFSIZ (4 * 1024 * 1024)

struct fsAlphabetizeFoldersFiles {
    inline bool operator()(FileInfoEx a, FileInfoEx b) {
        if(a.isDirectory == b.isDirectory)
            return strcasecmp(a.name.c_str(), b.name.c_str()) < 0;
        else return a.isDirectory;
    }
};

bool fsShowProgress(const std::string operationStr, const std::string pathStr, u64 pos, u64 totalSize) {
    static u32 prevProgress = -1;
    u32 progress = (u32) ((pos * 100) / totalSize);
    if(prevProgress != progress) {
        prevProgress = progress;
        uiDisplayProgress(gpu::SCREEN_TOP, operationStr, uiTruncateString(pathStr, 36, 0) + "\nPress B to cancel.", true, progress);
    }

    hid::poll();
    return !hid::pressed(hid::BUTTON_B);
}

u64 fsGetFreeSpace() {
    FS_ArchiveResource resource;
    Result res = FSUSER_GetSdmcArchiveResource(&resource);
    return (res != 0) ? 0 : (u64) resource.clusterSize * (u64) resource.freeClusters;
}

bool fsExists(const std::string path) {
    FILE* fd = fopen(path.c_str(), "r");
    if(fd) {
        fclose(fd);
        return true;
    }

    return fsIsDirectory(path);
}

bool fsIsDirectory(const std::string path) {
    DIR* dir = opendir(path.c_str());
    if(dir) {
        closedir(dir);
        return true;
    }

    return false;
}

std::string fsGetFileName(const std::string path) {
    std::string::size_type slashPos = path.rfind('/');
    if(slashPos == std::string::npos) {
        return path;
    }

    return path.substr(slashPos + 1);
}

std::string fsGetExtension(const std::string path) {
    std::string::size_type dotPos = path.rfind('.');
    if(dotPos == std::string::npos) {
        return "";
    }

    return path.substr(dotPos + 1);
}

bool fsHasExtension(const std::string path, const std::string extension) {
    if(extension.empty()) {
        return true;
    }

    const std::string ext = fsGetExtension(path);
    return strcasecmp(ext.c_str(), extension.c_str()) == 0;
}

bool fsHasExtensions(const std::string path, const std::vector<std::string> extensions) {
    if(extensions.empty()) {
        return true;
    }

    const std::string ext = fsGetExtension(path);
    for(std::vector<std::string>::const_iterator it = extensions.begin(); it != extensions.end(); it++) {
        std::string extension = *it;
        if(strcasecmp(ext.c_str(), extension.c_str()) == 0) {
            return true;
        }
    }

    return false;
}

u32 fsGetFileSize(const std::string path) {
    struct stat st;
    stat(path.c_str(), &st);
    return (u32) st.st_size;
}

bool fsProvideData(const std::string path, u32 offset, u32 buffSize, std::function<bool(u32 &offset)> onLoop, std::function<bool(u8* data)> onUpdate) {
    if((onLoop == NULL) || (onUpdate == NULL)) {
        errno = ENOTSUP;
        return false;
    }
    if(!fsExists(path)) {
        errno = ENOENT;
        return false;
    }

    FILE* fp = fopen(path.c_str(), "rb");
    u8* buffer = (u8*) calloc(buffSize, 1);
    u8* bufferEnd = buffer + buffSize;

    u32 fileSize  = fsGetFileSize(path);
    u32 offsetPrev = (u32) -1;

    bool result = false;

    if((fp == NULL) || (buffer == NULL)) {
        if(fp != NULL) fclose(fp);
        if(buffer != NULL) free(buffer);
        return false;
    }

    while(core::running()) {
        if((offset != offsetPrev) && (offset <= fileSize)) {
            if(offset < offsetPrev) {
                u32 dataEnd = offset + buffSize;
                u32 overlap = (dataEnd > offsetPrev) ? dataEnd - offsetPrev : 0;
                memmove(bufferEnd - overlap, buffer, overlap);
                fseek(fp, offset, SEEK_SET);
                fread(buffer, 1, buffSize - overlap, fp);
            } else {
                u32 dataEnd = offset + buffSize;
                u32 dataEndPrev = offsetPrev + buffSize;
                u32 overlap = (dataEndPrev > offset) ? dataEndPrev - offset : 0;
                memmove(buffer, bufferEnd - overlap, overlap);
                if(dataEnd > fileSize) {
                    memset(buffer + overlap, 0x00, buffSize - overlap);
                }
                fseek(fp, offset + overlap, SEEK_SET);
                fread(buffer + overlap, 1, buffSize - overlap, fp);
            }
            offsetPrev = offset;
            if(onUpdate(buffer)) {
                result = true;
            }
        } else if(offset > fileSize) {
            offset = fileSize;
        } else if(onLoop(offset)) {
            result = true;
        }

        if(result) break;
    }

    if(fp != NULL) fclose(fp);
    if(buffer != NULL) free(buffer);

    return result;
}

bool fsPathDelete(const std::string path) {
    if(fsIsDirectory(path)) {
        std::vector<FileInfo> contents = fsGetDirectoryContents(path);
        for (std::vector<FileInfo>::iterator it = contents.begin(); it != contents.end(); it++)
            if (!fsPathDelete((*it).path)) return false;
        return (rmdir(path.c_str()) == 0);
    } else return (remove(path.c_str()) == 0);
}

bool fsPathCopy(const std::string path, const std::string dest, bool showProgress) {
    if(fsExists(dest)) {
        errno = EEXIST;
        return false;
    }
    if(showProgress && !fsShowProgress("Copying", path, 0, 1)) {
        errno = ECANCELED;
        return false;
    }
    if(fsIsDirectory(path)) {
        if(dest.find(path + "/") != std::string::npos) {
            errno = ENOTSUP;
            return false;
        }
        if(mkdir(dest.c_str(), 0777) != 0) return false;
        if(showProgress && !fsShowProgress("Copying", path, 1, 2)) {
            errno = ECANCELED;
            return false;
        }
        std::vector<FileInfo> contents = fsGetDirectoryContents(path);
        for (std::vector<FileInfo>::iterator it = contents.begin(); it != contents.end(); it++)
            if (!fsPathCopy((*it).path, dest + "/" + (*it).name, showProgress)) return false;
        return true;
    } else {
        bool ret = true;
        u64 total = fsGetFileSize(path);
        size_t l_bufsiz = (total < CTRX_BUFSIZ) ? total : CTRX_BUFSIZ;
        u8* buffer = (u8*) malloc( l_bufsiz );
        FILE* fp = fopen(path.c_str(), "rb");
        FILE* fd = fopen(dest.c_str(), "wb");
        if ((fp != NULL) && (fd != NULL) && (buffer != NULL)) {
            u64 pos = 0;
            size_t size;
            while ((size = fread(buffer, 1, l_bufsiz, fp)) > 0) {
                pos += fwrite(buffer, 1, size, fd);
                if(showProgress && !fsShowProgress("Copying", path, pos, total)) {
                    errno = ECANCELED;
                    ret = false;
                    break;
                }
            }
            ret = ret && (pos == total);
        }
        if(buffer != NULL) free(buffer);
        if(fp != NULL) fclose(fp);
        if(fd != NULL) fclose(fd);
        return ret;
    }
}

bool fsPathRename(const std::string path, const std::string dest) {
    if(dest.find(path + "/") != std::string::npos) {
        errno = ENOTSUP;
        return false;
    }
    if(fsExists(dest)) {
        errno = EEXIST;
        return false;
    }
    return (rename(path.c_str(), dest.c_str()) == 0);
}

bool fsCreateDir(const std::string path) {
    if(fsExists(path)) {
        errno = EEXIST;
        return false;
    }
    return (mkdir(path.c_str(), 0777) == 0);
}

bool fsCreateDummyFile(const std::string path, u64 size, u16 content, bool showProgress) {
    if(fsExists(path)) {
        errno = EEXIST;
        return false;
    }
    if(size < CTRX_BUFSIZ) showProgress = false;
    if(showProgress) fsShowProgress("Generating", path, 0, 1);
    bool ret = false;
    size_t l_bufsiz = (size < CTRX_BUFSIZ) ? size : CTRX_BUFSIZ;
    u8* buffer = (u8*) malloc( l_bufsiz );
    FILE* fp = fopen(path.c_str(), "wb");
    if((fp != NULL) && (buffer != NULL)) {
        if(content & 0xFF00) {
            u8 byte = content & 0xFF;
            u8 inc = (content >> 8) & 0xFF;
            for(u64 count = 0; count < l_bufsiz; count++, byte += inc)
                buffer[count] = byte;
        } else memset(buffer, content, l_bufsiz);
        u64 pos = 0;
        for(u64 count = 0; count < size; count += l_bufsiz) {
            if(size - count < l_bufsiz) l_bufsiz = size - count;
            pos += fwrite(buffer, 1, l_bufsiz, fp);
            if(showProgress && !fsShowProgress("Generating", path, pos, size)) {
                errno = ECANCELED;
                break;
            }
        }
        ret = (pos == size);
    }
    if(buffer != NULL) free(buffer);
    if(fp != NULL) fclose(fp);
    return ret;
}

std::vector<FileInfo> fsGetDirectoryContents(const std::string directory) {
    std::vector<FileInfo> result;
    bool hasSlash = directory.size() != 0 && directory[directory.size() - 1] == '/';
    const std::string dirWithSlash = hasSlash ? directory : directory + "/";

    DIR* dir = opendir(dirWithSlash.c_str());
    if(dir == NULL) {
        return result;
    }

    while(true) {
        struct dirent* ent = readdir(dir);
        if(ent == NULL) {
            break;
        }
        result.push_back({dirWithSlash + std::string(ent->d_name), std::string(ent->d_name)});
    }

    closedir(dir);
    return result;
}

std::vector<FileInfoEx> fsGetDirectoryContentsEx(const std::string directory) {
    std::vector<FileInfoEx> result;
    bool hasSlash = directory.size() != 0 && directory[directory.size() - 1] == '/';
    const std::string dirWithSlash = hasSlash ? directory : directory + "/";

    DIR* dir = opendir(dirWithSlash.c_str());
    if(dir == NULL) {
        return result;
    }

    while(true) {
        struct dirent* ent = readdir(dir);
        if(ent == NULL) {
            break;
        }
        const std::string name = std::string(ent->d_name);
        if((name.compare(".") != 0) && (name.compare("..") != 0)) {
            const std::string path = dirWithSlash + std::string(ent->d_name);
            bool isDirectory = fsIsDirectory(path);
            result.push_back({path, std::string(ent->d_name), isDirectory});
        }
    }

    closedir(dir);
    std::sort(result.begin(), result.end(), fsAlphabetizeFoldersFiles());
    return result;
}
<|endoftext|>


<commit_before>#include "hal/Drive.hpp"

using namespace hal;

Drive::Drive(){

}

int Drive::initialize(
		const arg::SourceFilePath path
		){

	if( fileno() < 0 ){
		if( open(
				 arg::FilePath(path.argument()),
				 fs::OpenFlags::read_write()
				 ) < 0 ){
			return return_value();
		}
	}

	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_INIT;
	return set_attributes(attr);
}

int Drive::powerup() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_POWERUP;
	return set_attributes(attr);
}

int Drive::powerdown() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_POWERDOWN;
	return set_attributes(attr);
}

int Drive::reset() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_RESET;
	return set_attributes(attr);
}

int Drive::protect() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_PROTECT;
	return set_attributes(attr);
}

int Drive::unprotect() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_UNPROTECT;
	return set_attributes(attr);
}

int Drive::erase_blocks(u32 start, u32 end) const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_ERASE_BLOCKS;
	attr.start = start;
	attr.end = end;
	return set_attributes(attr);
}

int Drive::erase_device() const {
	drive_attr_t attr;
	DriveInfo info = get_info();
	if( info.o_flags() & DRIVE_FLAG_ERASE_DEVICE ){
		attr.o_flags = DRIVE_FLAG_ERASE_DEVICE;
		return set_attributes(attr);
	}

	u32 address = 0;
	while( address < info.write_block_count() ){
		printf("-- erasing at %ld\n", address);
		if( erase_blocks(address, info.write_block_count()) < 0 ){
			return return_value();
		}
		address += return_value();
		while( is_busy() ){
			chrono::wait(
						info.erase_block_time()
						);
		}
	}
	return 0;
}

bool Drive::is_busy() const {
	int result = ioctl(arg::IoRequest(I_DRIVE_ISBUSY));
	return result > 0;
}

DriveInfo Drive::get_info() const {
	drive_info_t info;
	if( ioctl(
			 arg::IoRequest(I_DRIVE_GETINFO),
			 arg::IoArgument(&info)
			 ) < 0 ){
		return DriveInfo();
	}
	return DriveInfo(info);
}

int Drive::set_attributes(const drive_attr_t & attributes) const {
	return ioctl(
				arg::IoRequest(I_DRIVE_SETATTR),
				arg::IoConstArgument(&attributes)
				);
}

<commit_msg>Update Drive.cpp<commit_after>#include "hal/Drive.hpp"

using namespace hal;

Drive::Drive(){

}

int Drive::initialize(
		const arg::SourceFilePath path
		){

	if( fileno() < 0 ){
		if( open(
				 arg::FilePath(path.argument()),
				 fs::OpenFlags::read_write()
				 ) < 0 ){
			return return_value();
		}
	}

	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_INIT;
	return set_attributes(attr);
}

int Drive::powerup() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_POWERUP;
	return set_attributes(attr);
}

int Drive::powerdown() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_POWERDOWN;
	return set_attributes(attr);
}

int Drive::reset() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_RESET;
	return set_attributes(attr);
}

int Drive::protect() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_PROTECT;
	return set_attributes(attr);
}

int Drive::unprotect() const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_UNPROTECT;
	return set_attributes(attr);
}

int Drive::erase_blocks(u32 start, u32 end) const {
	drive_attr_t attr;
	attr.o_flags = DRIVE_FLAG_ERASE_BLOCKS;
	attr.start = start;
	attr.end = end;
	return set_attributes(attr);
}

int Drive::erase_device() const {
	drive_attr_t attr;
	DriveInfo info = get_info();
	if( info.o_flags() & DRIVE_FLAG_ERASE_DEVICE ){
		attr.o_flags = DRIVE_FLAG_ERASE_DEVICE;
		return set_attributes(attr);
	}

	u32 address = 0;
	while( address < info.write_block_count() ){
		if( erase_blocks(address, info.write_block_count()) < 0 ){
			return return_value();
		}
		address += return_value();
		while( is_busy() ){
			chrono::wait(
						info.erase_block_time()
						);
		}
	}
	return 0;
}

bool Drive::is_busy() const {
	int result = ioctl(arg::IoRequest(I_DRIVE_ISBUSY));
	return result > 0;
}

DriveInfo Drive::get_info() const {
	drive_info_t info;
	if( ioctl(
			 arg::IoRequest(I_DRIVE_GETINFO),
			 arg::IoArgument(&info)
			 ) < 0 ){
		return DriveInfo();
	}
	return DriveInfo(info);
}

int Drive::set_attributes(const drive_attr_t & attributes) const {
	return ioctl(
				arg::IoRequest(I_DRIVE_SETATTR),
				arg::IoConstArgument(&attributes)
				);
}

<|endoftext|>


<commit_before>/**
 * Unit tests for MIPS register
 * @author Alexander Misevich
 * Copyright 2018 MIPT-MIPS
 */

// generic C
#include <cassert>
#include <cstdlib>
#include <sstream>

// Catch2
#include <catch.hpp>

// MIPT-MIPS modules
#include "../mips_register.h"

static_assert(MIPSRegister::MAX_REG >= 32);

// Testing methods of the class
TEST_CASE( "MIPS_registers: ID_converters")
{
    for ( uint8 i = 0; i < 32; ++i)
        CHECK( MIPSRegister::from_cpu_index(i).to_rf_index() == i);

    for ( uint8 i = 0; i < 32; ++i) {
        CHECK( MIPSRegister::from_cp0_index(i).to_rf_index() > 32);
        CHECK( !MIPSRegister::from_cp0_index(i).is_mips_lo());
        CHECK( !MIPSRegister::from_cp0_index(i).is_mips_hi());
    }
}

TEST_CASE( "MIPS_registers: GDB_ID_converter")
{
    for ( uint8 i = 0; i < 32; ++i)
        CHECK( MIPSRegister::from_gdb_index(i) == MIPSRegister::from_cpu_index(i));
    CHECK( MIPSRegister::from_gdb_index(32) == MIPSRegister::from_cp0_index(12));  // SR
    CHECK( MIPSRegister::from_gdb_index(33) == MIPSRegister::mips_lo());
    CHECK( MIPSRegister::from_gdb_index(34) == MIPSRegister::mips_hi());
    CHECK( MIPSRegister::from_gdb_index(35) == MIPSRegister::from_cp0_index( 8));  // BadVAddr
    CHECK( MIPSRegister::from_gdb_index(36) == MIPSRegister::cause());
}

TEST_CASE( "MIPS_registers: CP1_ID_converter")
{
    for ( uint8 i = 0; i < 32; ++i)
    {
        CHECK( MIPSRegister::from_cp1_index(i).to_rf_index() > 32);
        CHECK( MIPSRegister::from_cp1_index(i).to_rf_index() >
               MIPSRegister::from_cp0_index(i).to_rf_index());
    }

    std::ostringstream oss;
    oss << MIPSRegister::from_cp1_index(3);
    CHECK( oss.str() == "f3");
}

TEST_CASE( "MIPS_registers: Equal")
{
    for ( uint8 i = 0; i < 32; ++i)
    {
        CHECK(MIPSRegister::from_cpu_index(i) == MIPSRegister::from_cpu_index(i));
        if (i > 0) {
            CHECK(MIPSRegister::from_cpu_index(i - 1) != MIPSRegister::from_cpu_index(i));
        }
    }
}

TEST_CASE( "MIPS_registers: Hi_Lo_impossible")
{
    for ( uint8 i = 0; i < 32; ++i)
    {
        auto reg = MIPSRegister::from_cpu_index(i);
        CHECK_FALSE(reg.is_mips_hi());
        CHECK_FALSE(reg.is_mips_lo());
    }
}

TEST_CASE( "MIPS_registers: Zero")
{
    auto reg = MIPSRegister::zero();
    CHECK(reg.is_zero());
    CHECK_FALSE(reg.is_mips_hi());
    CHECK_FALSE(reg.is_mips_lo());
    CHECK(reg.to_rf_index() == 0);
}

TEST_CASE( "MIPS_registers: Return_address")
{
    auto reg = MIPSRegister::return_address();
    CHECK_FALSE(reg.is_zero());
    CHECK_FALSE(reg.is_mips_hi());
    CHECK_FALSE(reg.is_mips_lo());
    CHECK(reg.to_rf_index() == 31);
}

TEST_CASE( "MIPS_registers: Hi_register")
{
    auto reg = MIPSRegister::mips_hi();
    CHECK_FALSE(reg.is_zero());
    CHECK(reg.is_mips_hi());
    CHECK_FALSE(reg.is_mips_lo());
    CHECK_FALSE(reg.to_rf_index() < 32);
}

TEST_CASE( "MIPS_registers: Lo_register")
{
    auto reg = MIPSRegister::mips_lo();
    CHECK_FALSE(reg.is_zero());
    CHECK_FALSE(reg.is_mips_hi());
    CHECK(reg.is_mips_lo());
    CHECK_FALSE(reg.to_rf_index() < 32);
}

TEST_CASE( "MIPS_registers: no csr register")
{
    auto reg = MIPSRegister::from_csr_name( "balalaika");
    CHECK( reg.is_zero());
}

TEST_CASE( "MIPS_registers: CP0 registers")
{
    CHECK( MIPSRegister::cause().dump() == "Cause");
    CHECK( MIPSRegister::epc().dump() == "EPC");
    CHECK( MIPSRegister::status().dump() == "SR");
}
<commit_msg>Add unit test for GDB 1000th register (#1068)<commit_after>/**
 * Unit tests for MIPS register
 * @author Alexander Misevich
 * Copyright 2018 MIPT-MIPS
 */

// generic C
#include <cassert>
#include <cstdlib>
#include <sstream>

// Catch2
#include <catch.hpp>

// MIPT-MIPS modules
#include "../mips_register.h"

static_assert(MIPSRegister::MAX_REG >= 32);

// Testing methods of the class
TEST_CASE( "MIPS_registers: ID_converters")
{
    for ( uint8 i = 0; i < 32; ++i)
        CHECK( MIPSRegister::from_cpu_index(i).to_rf_index() == i);

    for ( uint8 i = 0; i < 32; ++i) {
        CHECK( MIPSRegister::from_cp0_index(i).to_rf_index() > 32);
        CHECK( !MIPSRegister::from_cp0_index(i).is_mips_lo());
        CHECK( !MIPSRegister::from_cp0_index(i).is_mips_hi());
    }
}

TEST_CASE( "MIPS_registers: GDB_ID_converter")
{
    for ( uint8 i = 0; i < 32; ++i)
        CHECK( MIPSRegister::from_gdb_index(i) == MIPSRegister::from_cpu_index(i));
    CHECK( MIPSRegister::from_gdb_index(32) == MIPSRegister::from_cp0_index(12));  // SR
    CHECK( MIPSRegister::from_gdb_index(33) == MIPSRegister::mips_lo());
    CHECK( MIPSRegister::from_gdb_index(34) == MIPSRegister::mips_hi());
    CHECK( MIPSRegister::from_gdb_index(35) == MIPSRegister::from_cp0_index( 8));  // BadVAddr
    CHECK( MIPSRegister::from_gdb_index(36) == MIPSRegister::cause());
    CHECK( MIPSRegister::from_gdb_index(1000) == MIPSRegister::zero());
}

TEST_CASE( "MIPS_registers: CP1_ID_converter")
{
    for ( uint8 i = 0; i < 32; ++i)
    {
        CHECK( MIPSRegister::from_cp1_index(i).to_rf_index() > 32);
        CHECK( MIPSRegister::from_cp1_index(i).to_rf_index() >
               MIPSRegister::from_cp0_index(i).to_rf_index());
    }

    std::ostringstream oss;
    oss << MIPSRegister::from_cp1_index(3);
    CHECK( oss.str() == "f3");
}

TEST_CASE( "MIPS_registers: Equal")
{
    for ( uint8 i = 0; i < 32; ++i)
    {
        CHECK(MIPSRegister::from_cpu_index(i) == MIPSRegister::from_cpu_index(i));
        if (i > 0) {
            CHECK(MIPSRegister::from_cpu_index(i - 1) != MIPSRegister::from_cpu_index(i));
        }
    }
}

TEST_CASE( "MIPS_registers: Hi_Lo_impossible")
{
    for ( uint8 i = 0; i < 32; ++i)
    {
        auto reg = MIPSRegister::from_cpu_index(i);
        CHECK_FALSE(reg.is_mips_hi());
        CHECK_FALSE(reg.is_mips_lo());
    }
}

TEST_CASE( "MIPS_registers: Zero")
{
    auto reg = MIPSRegister::zero();
    CHECK(reg.is_zero());
    CHECK_FALSE(reg.is_mips_hi());
    CHECK_FALSE(reg.is_mips_lo());
    CHECK(reg.to_rf_index() == 0);
}

TEST_CASE( "MIPS_registers: Return_address")
{
    auto reg = MIPSRegister::return_address();
    CHECK_FALSE(reg.is_zero());
    CHECK_FALSE(reg.is_mips_hi());
    CHECK_FALSE(reg.is_mips_lo());
    CHECK(reg.to_rf_index() == 31);
}

TEST_CASE( "MIPS_registers: Hi_register")
{
    auto reg = MIPSRegister::mips_hi();
    CHECK_FALSE(reg.is_zero());
    CHECK(reg.is_mips_hi());
    CHECK_FALSE(reg.is_mips_lo());
    CHECK_FALSE(reg.to_rf_index() < 32);
}

TEST_CASE( "MIPS_registers: Lo_register")
{
    auto reg = MIPSRegister::mips_lo();
    CHECK_FALSE(reg.is_zero());
    CHECK_FALSE(reg.is_mips_hi());
    CHECK(reg.is_mips_lo());
    CHECK_FALSE(reg.to_rf_index() < 32);
}

TEST_CASE( "MIPS_registers: no csr register")
{
    auto reg = MIPSRegister::from_csr_name( "balalaika");
    CHECK( reg.is_zero());
}

TEST_CASE( "MIPS_registers: CP0 registers")
{
    CHECK( MIPSRegister::cause().dump() == "Cause");
    CHECK( MIPSRegister::epc().dump() == "EPC");
    CHECK( MIPSRegister::status().dump() == "SR");
}
<|endoftext|>


<commit_before>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#include "Physics.h"
#include "ShapeCapsule.h"
#include "ActorBase.h"
#include "Visualizer.h"
#include "sys/SysControl.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

	SetEnabled(1);
	SetViewDirection(vec3(0.0f, 1.0f, 0.0f));
	SetCollision(1);
	SetCollisionRadius(0.3f);
	SetCollisionHeight(1.0f);
	SetFriction(2.0f);
	SetMinVelocity(2.0f);
	SetMaxVelocity(4.0f);
	SetAcceleration(8.0f);
	SetDamping(8.0f);
	SetJumping(1.5f);

	SetGround(0);
	SetCeiling(0);

}
CActorBase::~CActorBase()
{
	m_pDummy->SetObject(NULL);
	delete m_pObject;
	delete m_pDummy;
}

void CActorBase::SetEnabled(int enable)
{
	m_nEnable = enable;
	m_pDummy->SetEnabled(m_nEnable);
}
int CActorBase::IsEnabled() const
{
	return m_nEnable;
}
void CActorBase::Update(float ifps)
{
	if (!m_nEnable)
	{
		return;
	}
	// impulse
	vec3 impulse = vec3_zero;

	// ortho basis
	vec3 tangent, binormal;
	OrthoBasis(m_vUp, tangent, binormal);
	// current basis
	vec3 x = quat(m_vUp, -m_fPhiAngle) * binormal;
	vec3 y = Normalize(Cross(m_vUp, x));
	vec3 z = Normalize(Cross(x, y));
	// handle states
	Update_States(1, ifps);

	// old velocity
	float x_velocity = Dot(x, m_vVelocity);
	float y_velocity = Dot(y, m_vVelocity);
	float z_velocity = Dot(z, m_vVelocity);

	// movement
	if (m_pStates[STATE_FORWARD]) impulse += x;
	if (m_pStates[STATE_BACKWARD]) impulse -= x;
	if (m_pStates[STATE_MOVE_LEFT]) impulse += y;
	if (m_pStates[STATE_MOVE_RIGHT]) impulse -= y;
	impulse.normalize();
	// velocity
	if (m_pStates[STATE_RUN]) impulse *= m_fMaxVelocity;
	else impulse *= m_fMinVelocity;

	// jump
	if (m_pStates[STATE_JUMP] == STATE_BEGIN)
	{
		impulse += z * CMathCore::Sqrt(2.0f * 9.8f * m_fJumping) / (m_fAcceleration * ifps);
	}

	// rotate velocity
	if (GetGround())
	{
		m_vVelocity = x * x_velocity + y * y_velocity + z * z_velocity;
	}
	// time
	float time = ifps * g_Engine.pPhysics->GetScale();
	// target velocity
	float target_velocity = Length(vec2(Dot(x, impulse), Dot(y, impulse)));

	// penetration tolerance
	float penetration = g_Engine.pPhysics->GetPenetrationTolerance();
	float penetration_2 = penetration * 2.0f;

	// frozen linear velocity
	float frozen_velocity = g_Engine.pPhysics->GetFrozenLinearVelocity();

	// friction
	float friction = 0.0f;
	if (target_velocity < EPSILON)
	{
		friction = m_fFriction;
	}

	// clear collision flags
	if (GetCollision())
	{
		m_nGround = 0;
		m_nCeiling = 0;
	}

	// movement
	do
	{
		// adaptive time step
		float ifps = Min(time, ACTOR_BASE_IFPS);
		time -= ifps;
		// save old velocity
		float old_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		// integrate velocity
		m_vVelocity += impulse * (m_fAcceleration * ifps);
		m_vVelocity += g_Engine.pPhysics->GetGravity() * ifps;

		// damping
		float current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));
		if (target_velocity < EPSILON || current_velocity > target_velocity)
		{
			m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * CMathCore::Exp(-m_fDamping * ifps) + z * Dot(z, m_vVelocity);
		}

		// clamp maximum velocity
		current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		if (current_velocity > old_velocity)
		{
			if (current_velocity > target_velocity)
			{
				m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * target_velocity / current_velocity + z * Dot(z, m_vVelocity);
			}
		}
		// integrate position
		//m_vPosition += Vec3(m_vVelocity * ifps);
		if (GetCollision())
		{
			// get collision
			vec3 tangent, binormal;
			const Vec3 *caps = m_pShape->GetCaps();
			for (int i = 0; i < ACTOR_BASE_COLLISIONS; i++)
			{
				m_pDummy->SetTransform(Get_Body_Transform());
				m_pShape->GetCollision(m_vecContacts, 0.0f);

				if (m_vecContacts.Size() == 0) break;
				float inum_contacts = 1.0f / CMathCore::Itof(m_vecContacts.Size());
				for (int j = 0; j < m_vecContacts.Size(); j++)
				{
					const CShape::Contact &c = m_vecContacts[j];

					vec3 normalCollision = c.normal;
					if (is_frozen && c.depth < penetration_2)
					{
						m_vPosition += Vec3(z * (Max(c.depth - penetration, 0.0f) * inum_contacts * Dot(z, normalCollision)));
					}
					else
					{
						m_vPosition += Vec3(normalCollision * (Max(c.depth - penetration, 0.0f) * inum_contacts));
						is_frozen = 0;
					}
					float normal_velocity = Dot(normalCollision, m_vVelocity);
					if (normal_velocity < 0.0f)
					{
						m_vVelocity -= normalCollision * normal_velocity;
					}
					if (friction > EPSILON)
					{
						OrthoBasis(c.normal, tangent, binormal);
						float tangent_velocity = Dot(tangent, m_vVelocity);
						float binormal_velocity = Dot(binormal, m_vVelocity);
						if (CMathCore::Abs(tangent_velocity) > EPSILON || CMathCore::Abs(binormal_velocity) > EPSILON)
						{
							float friction_velocity = Clamp(Max(-normal_velocity, 0.0f) * friction * CMathCore::RSqrt(tangent_velocity * tangent_velocity + binormal_velocity * binormal_velocity), -1.0f, 1.0f);
							m_vVelocity -= tangent * tangent_velocity * friction_velocity;
							m_vVelocity -= binormal * binormal_velocity * friction_velocity;

						}
					}
					if (Dot(c.normal, m_vUp) > 0.5f && Dot(vec3(c.point - caps[0]), m_vUp) < 0.0f) m_nGround = 1;
					if (Dot(c.normal, m_vUp) < -0.5f && Dot(vec3(c.point - caps[1]), m_vUp) > 0.0f) m_nCeiling = 1;
				}
			}
		}

		m_vPosition += Vec3(m_vVelocity * ifps);
	} while (time > EPSILON);

	// current position
	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_WorldBoundBox.Set(m_BoundBox, Translate(m_vPosition));
	m_WorldBoundSphere.Set(m_BoundSphere, Translate(m_vPosition));
}
/******************************************************************************\
*
* Parameters
*
\******************************************************************************/
/*
*/
void CActorBase::Update_Bounds()
{
	float radius = m_pShape->GetRadius();
	float hheight = m_pShape->GetHHeight();
	m_BoundBox.Set(vec3(-radius, -radius, 0.0f), vec3(radius, radius, (radius + hheight) * 2.0f));
	m_BoundSphere.Set(vec3(0.0f, 0.0f, radius + hheight), radius + hheight);

	m_WorldBoundBox.Set(m_BoundBox, Translate(m_vPosition));
	m_WorldBoundSphere.Set(m_BoundSphere, Translate(m_vPosition));
}
/*
*/
void CActorBase::SetIntersectionMask(int mask)
{
	m_pShape->SetIntersectionMask(mask);
}
int CActorBase::GetIntersectionMask() const
{
	return m_pShape->GetIntersectionMask();
}

/*
*/
void CActorBase::SetCollision(int c)
{
	m_nCollision = c;
}
int CActorBase::GetCollision() const
{
	return m_nCollision;
}
void CActorBase::SetCollisionMask(int mask)
{
	m_pShape->SetCollisionMask(mask);
}
int CActorBase::GetCollisionMask() const
{
	return m_pShape->GetCollisionMask();
}

/*
*/
void CActorBase::SetCollisionRadius(float radius)
{
	if (!Compare(m_pShape->GetRadius(), radius))
	{
		m_pDummy->SetPreserveTransform(Mat4(Translate(m_vUp * (radius - m_pShape->GetRadius()))) * m_pDummy->GetTransform());
		m_pShape->SetRadius(radius);
	}
	Update_Bounds();
}
float CActorBase::GetCollisionRadius() const
{
	return m_pShape->GetRadius();
}

void CActorBase::SetCollisionHeight(float height)
{
	if (!Compare(m_pShape->GetHeight(), height))
	{
		m_pDummy->SetPreserveTransform(Mat4(Translate(m_vUp * (height - m_pShape->GetHeight()) * 0.5f)) * m_pDummy->GetTransform());
		m_pShape->SetHeight(height);
	}
	Update_Bounds();
}
float CActorBase::GetCollisionHeight() const
{
	return m_pShape->GetHeight();
}

void CActorBase::SetMinVelocity(float velocity)
{
	m_fMinVelocity = Max(velocity, 0.0f);
}
float CActorBase::GetMinVelocity() const
{
	return m_fMinVelocity;
}

<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#include "Physics.h"
#include "ShapeCapsule.h"
#include "ActorBase.h"
#include "Visualizer.h"
#include "sys/SysControl.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

	SetEnabled(1);
	SetViewDirection(vec3(0.0f, 1.0f, 0.0f));
	SetCollision(1);
	SetCollisionRadius(0.3f);
	SetCollisionHeight(1.0f);
	SetFriction(2.0f);
	SetMinVelocity(2.0f);
	SetMaxVelocity(4.0f);
	SetAcceleration(8.0f);
	SetDamping(8.0f);
	SetJumping(1.5f);

	SetGround(0);
	SetCeiling(0);

}
CActorBase::~CActorBase()
{
	m_pDummy->SetObject(NULL);
	delete m_pObject;
	delete m_pDummy;
}

void CActorBase::SetEnabled(int enable)
{
	m_nEnable = enable;
	m_pDummy->SetEnabled(m_nEnable);
}
int CActorBase::IsEnabled() const
{
	return m_nEnable;
}
void CActorBase::Update(float ifps)
{
	if (!m_nEnable)
	{
		return;
	}
	// impulse
	vec3 impulse = vec3_zero;

	// ortho basis
	vec3 tangent, binormal;
	OrthoBasis(m_vUp, tangent, binormal);
	// current basis
	vec3 x = quat(m_vUp, -m_fPhiAngle) * binormal;
	vec3 y = Normalize(Cross(m_vUp, x));
	vec3 z = Normalize(Cross(x, y));
	// handle states
	Update_States(1, ifps);

	// old velocity
	float x_velocity = Dot(x, m_vVelocity);
	float y_velocity = Dot(y, m_vVelocity);
	float z_velocity = Dot(z, m_vVelocity);

	// movement
	if (m_pStates[STATE_FORWARD]) impulse += x;
	if (m_pStates[STATE_BACKWARD]) impulse -= x;
	if (m_pStates[STATE_MOVE_LEFT]) impulse += y;
	if (m_pStates[STATE_MOVE_RIGHT]) impulse -= y;
	impulse.normalize();
	// velocity
	if (m_pStates[STATE_RUN]) impulse *= m_fMaxVelocity;
	else impulse *= m_fMinVelocity;

	// jump
	if (m_pStates[STATE_JUMP] == STATE_BEGIN)
	{
		impulse += z * CMathCore::Sqrt(2.0f * 9.8f * m_fJumping) / (m_fAcceleration * ifps);
	}

	// rotate velocity
	if (GetGround())
	{
		m_vVelocity = x * x_velocity + y * y_velocity + z * z_velocity;
	}
	// time
	float time = ifps * g_Engine.pPhysics->GetScale();
	// target velocity
	float target_velocity = Length(vec2(Dot(x, impulse), Dot(y, impulse)));

	// penetration tolerance
	float penetration = g_Engine.pPhysics->GetPenetrationTolerance();
	float penetration_2 = penetration * 2.0f;

	// frozen linear velocity
	float frozen_velocity = g_Engine.pPhysics->GetFrozenLinearVelocity();

	// friction
	float friction = 0.0f;
	if (target_velocity < EPSILON)
	{
		friction = m_fFriction;
	}

	// clear collision flags
	if (GetCollision())
	{
		m_nGround = 0;
		m_nCeiling = 0;
	}

	// movement
	do
	{
		// adaptive time step
		float ifps = Min(time, ACTOR_BASE_IFPS);
		time -= ifps;
		// save old velocity
		float old_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		// integrate velocity
		m_vVelocity += impulse * (m_fAcceleration * ifps);
		m_vVelocity += g_Engine.pPhysics->GetGravity() * ifps;

		// damping
		float current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));
		if (target_velocity < EPSILON || current_velocity > target_velocity)
		{
			m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * CMathCore::Exp(-m_fDamping * ifps) + z * Dot(z, m_vVelocity);
		}

		// clamp maximum velocity
		current_velocity = Length(vec2(Dot(x, m_vVelocity), Dot(y, m_vVelocity)));

		if (current_velocity > old_velocity)
		{
			if (current_velocity > target_velocity)
			{
				m_vVelocity = (x * Dot(x, m_vVelocity) + y * Dot(y, m_vVelocity)) * target_velocity / current_velocity + z * Dot(z, m_vVelocity);
			}
		}
		// integrate position
		//m_vPosition += Vec3(m_vVelocity * ifps);
		if (GetCollision())
		{
			// get collision
			vec3 tangent, binormal;
			const Vec3 *caps = m_pShape->GetCaps();
			for (int i = 0; i < ACTOR_BASE_COLLISIONS; i++)
			{
				m_pDummy->SetTransform(Get_Body_Transform());
				m_pShape->GetCollision(m_vecContacts, 0.0f);

				if (m_vecContacts.Size() == 0) break;
				float inum_contacts = 1.0f / CMathCore::Itof(m_vecContacts.Size());
				for (int j = 0; j < m_vecContacts.Size(); j++)
				{
					const CShape::Contact &c = m_vecContacts[j];

					vec3 normalCollision = c.normal;
					if (is_frozen && c.depth < penetration_2)
					{
						m_vPosition += Vec3(z * (Max(c.depth - penetration, 0.0f) * inum_contacts * Dot(z, normalCollision)));
					}
					else
					{
						m_vPosition += Vec3(normalCollision * (Max(c.depth - penetration, 0.0f) * inum_contacts));
						is_frozen = 0;
					}
					float normal_velocity = Dot(normalCollision, m_vVelocity);
					if (normal_velocity < 0.0f)
					{
						m_vVelocity -= normalCollision * normal_velocity;
					}
					if (friction > EPSILON)
					{
						OrthoBasis(c.normal, tangent, binormal);
						float tangent_velocity = Dot(tangent, m_vVelocity);
						float binormal_velocity = Dot(binormal, m_vVelocity);
						if (CMathCore::Abs(tangent_velocity) > EPSILON || CMathCore::Abs(binormal_velocity) > EPSILON)
						{
							float friction_velocity = Clamp(Max(-normal_velocity, 0.0f) * friction * CMathCore::RSqrt(tangent_velocity * tangent_velocity + binormal_velocity * binormal_velocity), -1.0f, 1.0f);
							m_vVelocity -= tangent * tangent_velocity * friction_velocity;
							m_vVelocity -= binormal * binormal_velocity * friction_velocity;

						}
					}
					if (Dot(c.normal, m_vUp) > 0.5f && Dot(vec3(c.point - caps[0]), m_vUp) < 0.0f) m_nGround = 1;
					if (Dot(c.normal, m_vUp) < -0.5f && Dot(vec3(c.point - caps[1]), m_vUp) > 0.0f) m_nCeiling = 1;
				}
			}
		}

		m_vPosition += Vec3(m_vVelocity * ifps);
	} while (time > EPSILON);

	// current position
	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_WorldBoundBox.Set(m_BoundBox, Translate(m_vPosition));
	m_WorldBoundSphere.Set(m_BoundSphere, Translate(m_vPosition));
}
/******************************************************************************\
*
* Parameters
*
\******************************************************************************/
/*
*/
void CActorBase::Update_Bounds()
{
	float radius = m_pShape->GetRadius();
	float hheight = m_pShape->GetHHeight();
	m_BoundBox.Set(vec3(-radius, -radius, 0.0f), vec3(radius, radius, (radius + hheight) * 2.0f));
	m_BoundSphere.Set(vec3(0.0f, 0.0f, radius + hheight), radius + hheight);

	m_WorldBoundBox.Set(m_BoundBox, Translate(m_vPosition));
	m_WorldBoundSphere.Set(m_BoundSphere, Translate(m_vPosition));
}
/*
*/
void CActorBase::SetIntersectionMask(int mask)
{
	m_pShape->SetIntersectionMask(mask);
}
int CActorBase::GetIntersectionMask() const
{
	return m_pShape->GetIntersectionMask();
}

/*
*/
void CActorBase::SetCollision(int c)
{
	m_nCollision = c;
}
int CActorBase::GetCollision() const
{
	return m_nCollision;
}
void CActorBase::SetCollisionMask(int mask)
{
	m_pShape->SetCollisionMask(mask);
}
int CActorBase::GetCollisionMask() const
{
	return m_pShape->GetCollisionMask();
}

/*
*/
void CActorBase::SetCollisionRadius(float radius)
{
	if (!Compare(m_pShape->GetRadius(), radius))
	{
		m_pDummy->SetPreserveTransform(Mat4(Translate(m_vUp * (radius - m_pShape->GetRadius()))) * m_pDummy->GetTransform());
		m_pShape->SetRadius(radius);
	}
	Update_Bounds();
}
float CActorBase::GetCollisionRadius() const
{
	return m_pShape->GetRadius();
}

void CActorBase::SetCollisionHeight(float height)
{
	if (!Compare(m_pShape->GetHeight(), height))
	{
		m_pDummy->SetPreserveTransform(Mat4(Translate(m_vUp * (height - m_pShape->GetHeight()) * 0.5f)) * m_pDummy->GetTransform());
		m_pShape->SetHeight(height);
	}
	Update_Bounds();
}
float CActorBase::GetCollisionHeight() const
{
	return m_pShape->GetHeight();
}

void CActorBase::SetMinVelocity(float velocity)
{
	m_fMinVelocity = Max(velocity, 0.0f);
}
float CActorBase::GetMinVelocity() const
{
	return m_fMinVelocity;
}

void CActorBase::SetMaxVelocity(float velocity)
{
	m_fMaxVelocity = Max(velocity, 0.0f);
}
<|endoftext|>


<commit_before>//==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//

#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineExperimentalChecks.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"

using namespace clang;

namespace {
class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> {
public:
  static void *getTag();
  void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng);

private:
  llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
};
}

void *AnalyzerStatsChecker::getTag() {
  static int x = 0;
  return &x;
}

void clang::RegisterAnalyzerStatsChecker(GRExprEngine &Eng) {
  Eng.registerCheck(new AnalyzerStatsChecker());
}

void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
                                            BugReporter &B,
                                            GRExprEngine &Eng) {
  const CFG *C  = 0;
  const Decl *D = 0;
  const LocationContext *LC = 0;
  const SourceManager &SM = B.getSourceManager();

  // Iterate over explodedgraph
  for (ExplodedGraph::node_iterator I = G.nodes_begin();
      I != G.nodes_end(); ++I) {
    const ProgramPoint &P = I->getLocation();
    // Save the LocationContext if we don't have it already
    if (!LC)
      LC = P.getLocationContext();

    if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
      const CFGBlock *CB = BE->getDst();
      reachable.insert(CB);
    }
  }

  // Get the CFG and the Decl of this block
  C = LC->getCFG();
  D = LC->getAnalysisContext()->getDecl();

  unsigned total = 0, unreachable = 0;

  // Find CFGBlocks that were not covered by any node
  for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
    const CFGBlock *CB = *I;
    ++total;
    // Check if the block is unreachable
    if (!reachable.count(CB)) {
      ++unreachable;
    }
  }

  // We never 'reach' the entry block, so correct the unreachable count
  unreachable--;

  // Generate the warning string
  llvm::SmallString<128> buf;
  llvm::raw_svector_ostream output(buf);
  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
  output << Loc.getFilename() << " : ";

  if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
    const NamedDecl *ND = cast<NamedDecl>(D);
    output << ND;
  }
  else if (isa<BlockDecl>(D)) {
    output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
  }

  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
      << unreachable << " | Aborted Block: "
      << (Eng.wasBlockAborted() ? "no" : "yes")
      << " | Empty WorkList: "
      << (Eng.hasEmptyWorkList() ? "yes" : "no") << "\n";

  B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
      D->getLocation());
}
<commit_msg>Fix an inverse boolean and unnecessary new line in warning output from AnalyzerStatsChecker.<commit_after>//==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//

#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineExperimentalChecks.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"

using namespace clang;

namespace {
class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> {
public:
  static void *getTag();
  void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng);

private:
  llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
};
}

void *AnalyzerStatsChecker::getTag() {
  static int x = 0;
  return &x;
}

void clang::RegisterAnalyzerStatsChecker(GRExprEngine &Eng) {
  Eng.registerCheck(new AnalyzerStatsChecker());
}

void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
                                            BugReporter &B,
                                            GRExprEngine &Eng) {
  const CFG *C  = 0;
  const Decl *D = 0;
  const LocationContext *LC = 0;
  const SourceManager &SM = B.getSourceManager();

  // Iterate over explodedgraph
  for (ExplodedGraph::node_iterator I = G.nodes_begin();
      I != G.nodes_end(); ++I) {
    const ProgramPoint &P = I->getLocation();
    // Save the LocationContext if we don't have it already
    if (!LC)
      LC = P.getLocationContext();

    if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
      const CFGBlock *CB = BE->getDst();
      reachable.insert(CB);
    }
  }

  // Get the CFG and the Decl of this block
  C = LC->getCFG();
  D = LC->getAnalysisContext()->getDecl();

  unsigned total = 0, unreachable = 0;

  // Find CFGBlocks that were not covered by any node
  for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
    const CFGBlock *CB = *I;
    ++total;
    // Check if the block is unreachable
    if (!reachable.count(CB)) {
      ++unreachable;
    }
  }

  // We never 'reach' the entry block, so correct the unreachable count
  unreachable--;

  // Generate the warning string
  llvm::SmallString<128> buf;
  llvm::raw_svector_ostream output(buf);
  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
  output << Loc.getFilename() << " : ";

  if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
    const NamedDecl *ND = cast<NamedDecl>(D);
    output << ND;
  }
  else if (isa<BlockDecl>(D)) {
    output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
  }

  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
      << unreachable << " | Aborted Block: "
      << (Eng.wasBlockAborted() ? "yes" : "no")
      << " | Empty WorkList: "
      << (Eng.hasEmptyWorkList() ? "yes" : "no");

  B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
      D->getLocation());
}
<|endoftext|>


<commit_before>
#include <gtest/gtest.h>
#include <iostream>
#include "testing_helpers.h"
#include "g2log.hpp"
#include "g2logworker.hpp"
#include "std2_make_unique.hpp"
#include "g2logmessage.hpp"
#include <fstream>

using namespace std;
using namespace g2;

namespace testing_helpers {

   std::string g_mockFatal_message = {};
   int g_mockFatal_signal = -1;
   bool g_mockFatalWasCalled = false;

   std::string mockFatalMessage() {
      return g_mockFatal_message;
   }

   int mockFatalSignal() {
      return g_mockFatal_signal;
   }

   bool mockFatalWasCalled() {
      return g_mockFatalWasCalled;
   }

   void mockFatalCall(FatalMessagePtr fatal_message) {
      g_mockFatal_message = fatal_message.get()->toString();
      g_mockFatal_signal = fatal_message.get()->_signal_id;
      g_mockFatalWasCalled = true;
      LogMessagePtr message{fatal_message.release()};
      g2::internal::saveMessage(message); //fatal_message.copyToLogMessage());
   }

   void clearMockFatal() {
      g_mockFatal_message = {};
      g_mockFatal_signal = -1;
      g_mockFatalWasCalled = false;
   }

   bool removeFile(std::string path_to_file) {
      return (0 == std::remove(path_to_file.c_str()));
   }

   bool verifyContent(const std::string &total_text, std::string msg_to_find) {
      std::string content(total_text);
      size_t location = content.find(msg_to_find);
      return (location != std::string::npos);
   }

   std::string readFileToText(std::string filename) {
      std::ifstream in;
      in.open(filename.c_str(), std::ios_base::in);
      if (!in.is_open()) {
         return
         {
         }; // error just return empty string - test will 'fault'
      }
      std::ostringstream oss;
      oss << in.rdbuf();
      return oss.str();
   }

   size_t LogFileCleaner::size() {
      return logs_to_clean_.size();
   }

   LogFileCleaner::~LogFileCleaner() {
      std::lock_guard<std::mutex> lock(g_mutex);
      {
         for (const auto& file : logs_to_clean_) {
            if (!removeFile(file)) {
               ADD_FAILURE() << "UNABLE to remove: " << file << std::endl;
            }
         }
         logs_to_clean_.clear();
      } // mutex
   }

   void LogFileCleaner::addLogToClean(std::string path_to_log) {
      std::lock_guard<std::mutex> lock(g_mutex);
      {
         if (std::find(logs_to_clean_.begin(), logs_to_clean_.end(), path_to_log.c_str()) == logs_to_clean_.end())
            logs_to_clean_.push_back(path_to_log);
      }
   }

   ScopedLogger::ScopedLogger() : _currentWorker(g2::LogWorker::createWithNoSink()) { }
   ScopedLogger::~ScopedLogger() { }
   g2::LogWorker* ScopedLogger::get() { return _currentWorker.get();  }

   RestoreFileLogger::RestoreFileLogger(std::string directory)
   : _scope(new ScopedLogger), _handle(_scope->get()->addSink(std2::make_unique<g2::FileSink>("UNIT_TEST_LOGGER", directory), &g2::FileSink::fileWrite)) {
      using namespace g2;
      g2::initializeLogging(_scope->_currentWorker.get());
      clearMockFatal();
      internal::changeFatalInitHandlerForUnitTesting(&mockFatalCall);

      auto filename = _handle->call(&FileSink::fileName);
      if (!filename.valid()) ADD_FAILURE();
      _log_file = filename.get();
   }

   RestoreFileLogger::~RestoreFileLogger() {
      g2::internal::shutDownLogging();

      if (!removeFile(_log_file))
         ADD_FAILURE();
   }

   std::string RestoreFileLogger::logFile() {
     if (_scope) {
       // beware for race condition
       // example:
       //         LOG(INFO) << ...
       //     auto file =    logger.logFile()
       //     auto content = ReadContentFromFile(file)
       // ... it is not guaranteed that the content will contain (yet) the LOG(INFO)
       std::future<std::string> filename = _handle->call(&g2::FileSink::fileName);
       _log_file = filename.get();
     }
     return _log_file;
  }

   // Beware of race between LOG(...) and this function.
   // since LOG(...) passes two queues but the handle::call only passes one queue
   // the handle::call can happen faster
   std::string RestoreFileLogger::resetAndRetrieveContent() {
      std::future<std::string> filename = _handle->call(&g2::FileSink::fileName);
      reset(); // flush all queues to sinks
      EXPECT_TRUE(filename.valid());
      auto file = filename.get();
      return readFileToText(file);
   }

} // testing_helpers
<commit_msg>merging heads 1 of 2<commit_after>
#include <gtest/gtest.h>
#include <iostream>
#include "testing_helpers.h"
#include "g2log.hpp"
#include "g2logworker.hpp"
#include "std2_make_unique.hpp"
#include "g2logmessage.hpp"
#include <fstream>

using namespace std;
using namespace g2;

namespace testing_helpers {

   std::string g_mockFatal_message = {};
   int g_mockFatal_signal = -1;
   bool g_mockFatalWasCalled = false;

   std::string mockFatalMessage() {
      return g_mockFatal_message;
   }

   int mockFatalSignal() {
      return g_mockFatal_signal;
   }

   bool mockFatalWasCalled() {
      return g_mockFatalWasCalled;
   }

   void mockFatalCall(FatalMessagePtr fatal_message) {
      g_mockFatal_message = fatal_message.get()->toString();
      g_mockFatal_signal = fatal_message.get()->_signal_id;
      g_mockFatalWasCalled = true;
      LogMessagePtr message{fatal_message.release()};
      g2::internal::saveMessage(message); //fatal_message.copyToLogMessage());
   }

   void clearMockFatal() {
      g_mockFatal_message.clear();
      g_mockFatal_signal = -1;
      g_mockFatalWasCalled = false;
   }

   bool removeFile(std::string path_to_file) {
      return (0 == std::remove(path_to_file.c_str()));
   }

   bool verifyContent(const std::string &total_text, std::string msg_to_find) {
      std::string content(total_text);
      size_t location = content.find(msg_to_find);
      return (location != std::string::npos);
   }

   std::string readFileToText(std::string filename) {
      std::ifstream in;
      in.open(filename.c_str(), std::ios_base::in);
      if (!in.is_open()) {
         return
         {
         }; // error just return empty string - test will 'fault'
      }
      std::ostringstream oss;
      oss << in.rdbuf();
      return oss.str();
   }

   size_t LogFileCleaner::size() {
      return logs_to_clean_.size();
   }

   LogFileCleaner::~LogFileCleaner() {
      std::lock_guard<std::mutex> lock(g_mutex);
      {
         for (const auto& file : logs_to_clean_) {
            if (!removeFile(file)) {
               ADD_FAILURE() << "UNABLE to remove: " << file << std::endl;
            }
         }
         logs_to_clean_.clear();
      } // mutex
   }

   void LogFileCleaner::addLogToClean(std::string path_to_log) {
      std::lock_guard<std::mutex> lock(g_mutex);
      {
         if (std::find(logs_to_clean_.begin(), logs_to_clean_.end(), path_to_log.c_str()) == logs_to_clean_.end())
            logs_to_clean_.push_back(path_to_log);
      }
   }

   ScopedLogger::ScopedLogger() : _currentWorker(g2::LogWorker::createWithNoSink()) { }
   ScopedLogger::~ScopedLogger() { }
   g2::LogWorker* ScopedLogger::get() { return _currentWorker.get();  }

   RestoreFileLogger::RestoreFileLogger(std::string directory)
   : _scope(new ScopedLogger), _handle(_scope->get()->addSink(std2::make_unique<g2::FileSink>("UNIT_TEST_LOGGER", directory), &g2::FileSink::fileWrite)) {
      using namespace g2;
      g2::initializeLogging(_scope->_currentWorker.get());
      clearMockFatal();
      internal::changeFatalInitHandlerForUnitTesting(&mockFatalCall);

      auto filename = _handle->call(&FileSink::fileName);
      if (!filename.valid()) ADD_FAILURE();
      _log_file = filename.get();
   }

   RestoreFileLogger::~RestoreFileLogger() {
      g2::internal::shutDownLogging();
      reset();

      if (!removeFile(_log_file))
         ADD_FAILURE();
   }

   std::string RestoreFileLogger::logFile() {
     if (_scope) {
       // beware for race condition
       // example:
       //         LOG(INFO) << ...
       //     auto file =    logger.logFile()
       //     auto content = ReadContentFromFile(file)
       // ... it is not guaranteed that the content will contain (yet) the LOG(INFO)
       std::future<std::string> filename = _handle->call(&g2::FileSink::fileName);
       _log_file = filename.get();
     }
     return _log_file;
  }

   // Beware of race between LOG(...) and this function.
   // since LOG(...) passes two queues but the handle::call only passes one queue
   // the handle::call can happen faster
   std::string RestoreFileLogger::resetAndRetrieveContent() {
      std::future<std::string> filename = _handle->call(&g2::FileSink::fileName);
      reset(); // flush all queues to sinks
      EXPECT_TRUE(filename.valid());
      auto file = filename.get();
      return readFileToText(file);
   }

} // testing_helpers
<|endoftext|>


<commit_before>//===-- sanitizer_platform_limits_linux.cc --------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of Sanitizer common code.
//
// Sizes and layouts of linux kernel data structures.
//===----------------------------------------------------------------------===//

// This is a separate compilation unit for linux headers that conflict with
// userspace headers.
// Most "normal" includes go in sanitizer_platform_limits_posix.cc

#include "sanitizer_platform.h"
#if SANITIZER_LINUX

#include "sanitizer_internal_defs.h"
#include "sanitizer_platform_limits_posix.h"

// For offsetof -> __builtin_offsetof definition.
#include <stddef.h>

// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that
// are not defined anywhere in userspace headers. Fake them. This seems to work
// fine with newer headers, too.
#include <asm/posix_types.h>
#define ino_t __kernel_ino_t
#define mode_t __kernel_mode_t
#define nlink_t __kernel_nlink_t
#define uid_t __kernel_uid_t
#define gid_t __kernel_gid_t
#define off_t __kernel_off_t
// This header seems to contain the definitions of _kernel_ stat* structs.
#include <asm/stat.h>
#undef ino_t
#undef mode_t
#undef nlink_t
#undef uid_t
#undef gid_t
#undef off_t

#include <linux/aio_abi.h>

#if SANITIZER_ANDROID
#include <asm/statfs.h>
#else
#include <sys/statfs.h>
#endif

#if !SANITIZER_ANDROID
#include <linux/perf_event.h>
#endif

namespace __sanitizer {
  unsigned struct_statfs64_sz = sizeof(struct statfs64);
}  // namespace __sanitizer

#if !defined(__powerpc64__)
COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
#endif

COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));

#if defined(__i386__)
COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
#endif

CHECK_TYPE_SIZE(io_event);
CHECK_SIZE_AND_OFFSET(io_event, data);
CHECK_SIZE_AND_OFFSET(io_event, obj);
CHECK_SIZE_AND_OFFSET(io_event, res);
CHECK_SIZE_AND_OFFSET(io_event, res2);

#if !SANITIZER_ANDROID
COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
               sizeof(struct perf_event_attr));
CHECK_SIZE_AND_OFFSET(perf_event_attr, type);
CHECK_SIZE_AND_OFFSET(perf_event_attr, size);
#endif

COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV);
COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV);

CHECK_TYPE_SIZE(iocb);
CHECK_SIZE_AND_OFFSET(iocb, aio_data);
// Skip aio_key, it's weird.
CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode);
CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio);
CHECK_SIZE_AND_OFFSET(iocb, aio_fildes);
CHECK_SIZE_AND_OFFSET(iocb, aio_buf);
CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes);
CHECK_SIZE_AND_OFFSET(iocb, aio_offset);

#endif  // SANITIZER_LINUX
<commit_msg>asan: fix android build android does not seem to have IOCB_CMD_PREADV<commit_after>//===-- sanitizer_platform_limits_linux.cc --------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of Sanitizer common code.
//
// Sizes and layouts of linux kernel data structures.
//===----------------------------------------------------------------------===//

// This is a separate compilation unit for linux headers that conflict with
// userspace headers.
// Most "normal" includes go in sanitizer_platform_limits_posix.cc

#include "sanitizer_platform.h"
#if SANITIZER_LINUX

#include "sanitizer_internal_defs.h"
#include "sanitizer_platform_limits_posix.h"

// For offsetof -> __builtin_offsetof definition.
#include <stddef.h>

// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that
// are not defined anywhere in userspace headers. Fake them. This seems to work
// fine with newer headers, too.
#include <asm/posix_types.h>
#define ino_t __kernel_ino_t
#define mode_t __kernel_mode_t
#define nlink_t __kernel_nlink_t
#define uid_t __kernel_uid_t
#define gid_t __kernel_gid_t
#define off_t __kernel_off_t
// This header seems to contain the definitions of _kernel_ stat* structs.
#include <asm/stat.h>
#undef ino_t
#undef mode_t
#undef nlink_t
#undef uid_t
#undef gid_t
#undef off_t

#include <linux/aio_abi.h>

#if SANITIZER_ANDROID
#include <asm/statfs.h>
#else
#include <sys/statfs.h>
#endif

#if !SANITIZER_ANDROID
#include <linux/perf_event.h>
#endif

namespace __sanitizer {
  unsigned struct_statfs64_sz = sizeof(struct statfs64);
}  // namespace __sanitizer

#if !defined(__powerpc64__)
COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
#endif

COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));

#if defined(__i386__)
COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
#endif

CHECK_TYPE_SIZE(io_event);
CHECK_SIZE_AND_OFFSET(io_event, data);
CHECK_SIZE_AND_OFFSET(io_event, obj);
CHECK_SIZE_AND_OFFSET(io_event, res);
CHECK_SIZE_AND_OFFSET(io_event, res2);

#if !SANITIZER_ANDROID
COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
               sizeof(struct perf_event_attr));
CHECK_SIZE_AND_OFFSET(perf_event_attr, type);
CHECK_SIZE_AND_OFFSET(perf_event_attr, size);
#endif

COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
#if !SANITIZER_ANDROID
COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV);
COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV);
#endif

CHECK_TYPE_SIZE(iocb);
CHECK_SIZE_AND_OFFSET(iocb, aio_data);
// Skip aio_key, it's weird.
CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode);
CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio);
CHECK_SIZE_AND_OFFSET(iocb, aio_fildes);
CHECK_SIZE_AND_OFFSET(iocb, aio_buf);
CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes);
CHECK_SIZE_AND_OFFSET(iocb, aio_offset);

#endif  // SANITIZER_LINUX
<|endoftext|>