<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_file_manager.h"

#include "base/file_util.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "net/base/io_buffer.h"

#if defined(OS_WIN)
#include "chrome/common/win_safe_util.h"
#elif defined(OS_MACOSX)
#include "chrome/browser/ui/cocoa/file_metadata.h"
#endif

namespace {

// Throttle updates to the UI thread so that a fast moving download doesn't
// cause it to become unresponsive (in milliseconds).
const int kUpdatePeriodMs = 500;

DownloadManager* DownloadManagerForRenderViewHost(int render_process_id,
                                                  int render_view_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
                                                       render_view_id);
  if (contents) {
    Profile* profile = contents->profile();
    if (profile)
      return profile->GetDownloadManager();
  }

  return NULL;
}

}  // namespace

DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh)
    : next_id_(0),
      resource_dispatcher_host_(rdh) {
}

DownloadFileManager::~DownloadFileManager() {
  DCHECK(downloads_.empty());
}

void DownloadFileManager::Shutdown() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(this, &DownloadFileManager::OnShutdown));
}

void DownloadFileManager::OnShutdown() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  StopUpdateTimer();
  STLDeleteValues(&downloads_);
}

void DownloadFileManager::CreateDownloadFile(DownloadCreateInfo* info,
                                             DownloadManager* download_manager,
                                             bool get_hash) {
  VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  scoped_ptr<DownloadFile>
      download_file(new DownloadFile(info, download_manager));
  if (!download_file->Initialize(get_hash)) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableFunction(&download_util::CancelDownloadRequest,
                            resource_dispatcher_host_,
                            info->child_id,
                            info->request_id));
    delete info;
    return;
  }

  DCHECK(GetDownloadFile(info->download_id) == NULL);
  downloads_[info->download_id] = download_file.release();
  // TODO(phajdan.jr): fix the duplication of path info below.
  info->path = info->save_info.file_path;

  // The file is now ready, we can un-pause the request and start saving data.
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest,
                        info->child_id, info->request_id));

  StartUpdateTimer();

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(download_manager,
                        &DownloadManager::StartDownload, info));
}

void DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // This balances the pause in DownloadResourceHandler::OnResponseStarted.
  resource_dispatcher_host_->PauseRequest(child_id, request_id, false);
}

DownloadFile* DownloadFileManager::GetDownloadFile(int id) {
  DownloadFileMap::iterator it = downloads_.find(id);
  return it == downloads_.end() ? NULL : it->second;
}

void DownloadFileManager::StartUpdateTimer() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  if (!update_timer_.IsRunning()) {
    update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
                        this, &DownloadFileManager::UpdateInProgressDownloads);
  }
}

void DownloadFileManager::StopUpdateTimer() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  update_timer_.Stop();
}

void DownloadFileManager::UpdateInProgressDownloads() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  for (DownloadFileMap::iterator i = downloads_.begin();
       i != downloads_.end(); ++i) {
    int id = i->first;
    DownloadFile* download_file = i->second;
    DownloadManager* manager = download_file->GetDownloadManager();
    if (manager) {
      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(manager, &DownloadManager::UpdateDownload,
                            id, download_file->bytes_so_far()));
    }
  }
}

// Called on the IO thread once the ResourceDispatcherHost has decided that a
// request is a download.
int DownloadFileManager::GetNextId() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  return next_id_++;
}

void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(info);

  DownloadManager* manager = DownloadManagerForRenderViewHost(
      info->child_id, info->render_view_id);
  if (!manager) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableFunction(&download_util::CancelDownloadRequest,
                            resource_dispatcher_host_,
                            info->child_id,
                            info->request_id));
    delete info;
    return;
  }

  manager->CreateDownloadItem(info);

  bool hash_needed = resource_dispatcher_host_->safe_browsing_service()->
      DownloadBinHashNeeded();

  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
                        info, make_scoped_refptr(manager), hash_needed));
}

// We don't forward an update to the UI thread here, since we want to throttle
// the UI update rate via a periodic timer. If the user has cancelled the
// download (in the UI thread), we may receive a few more updates before the IO
// thread gets the cancel message: we just delete the data since the
// DownloadFile has been deleted.
void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  std::vector<DownloadBuffer::Contents> contents;
  {
    base::AutoLock auto_lock(buffer->lock);
    contents.swap(buffer->contents);
  }

  DownloadFile* download = GetDownloadFile(id);
  for (size_t i = 0; i < contents.size(); ++i) {
    net::IOBuffer* data = contents[i].first;
    const int data_len = contents[i].second;
    if (download)
      download->AppendDataToFile(data->data(), data_len);
    data->Release();
  }
}

void DownloadFileManager::OnResponseCompleted(int id, DownloadBuffer* buffer) {
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  delete buffer;
  DownloadFileMap::iterator it = downloads_.find(id);
  if (it != downloads_.end()) {
    DownloadFile* download = it->second;
    download->Finish();

    DownloadManager* download_manager = download->GetDownloadManager();
    if (download_manager) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(
              download_manager, &DownloadManager::OnAllDataSaved,
              id, download->bytes_so_far()));
    }

    // We need to keep the download around until the UI thread has finalized
    // the name.
    if (download->path_renamed()) {
      downloads_.erase(it);
      delete download;
    }
  }

  if (downloads_.empty())
    StopUpdateTimer();
}

// This method will be sent via a user action, or shutdown on the UI thread, and
// run on the download thread. Since this message has been sent from the UI
// thread, the download may have already completed and won't exist in our map.
void DownloadFileManager::CancelDownload(int id) {
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  DownloadFileMap::iterator it = downloads_.find(id);
  if (it != downloads_.end()) {
    DownloadFile* download = it->second;
    VLOG(20) << __FUNCTION__ << "()"
             << " download = " << download->DebugString();
    download->Cancel();

    if (download->path_renamed()) {
      downloads_.erase(it);
      delete download;
    }
  }

  if (downloads_.empty())
    StopUpdateTimer();
}

void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  DCHECK(manager);

  std::set<DownloadFile*> to_remove;

  for (DownloadFileMap::iterator i = downloads_.begin();
       i != downloads_.end(); ++i) {
    DownloadFile* download_file = i->second;
    if (download_file->GetDownloadManager() == manager) {
      download_file->CancelDownloadRequest(resource_dispatcher_host_);
      to_remove.insert(download_file);
    }
  }

  for (std::set<DownloadFile*>::iterator i = to_remove.begin();
       i != to_remove.end(); ++i) {
    downloads_.erase((*i)->id());
    delete *i;
  }
}

// Actions from the UI thread and run on the download thread

// The DownloadManager in the UI thread has provided an intermediate .crdownload
// name for the download specified by 'id'. Rename the in progress download.
void DownloadFileManager::OnIntermediateDownloadName(
    int id, const FilePath& full_path, DownloadManager* download_manager)
{
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
           << " full_path = \"" << full_path.value() << "\"";
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  DownloadFileMap::iterator it = downloads_.find(id);
  if (it == downloads_.end())
    return;

  DownloadFile* download = it->second;
  VLOG(20) << __FUNCTION__ << "()" << " download = " << download->DebugString();
  if (!download->Rename(full_path, false /* is_final_rename */)) {
    // Error. Between the time the UI thread generated 'full_path' to the time
    // this code runs, something happened that prevents us from renaming.
    CancelDownloadOnRename(id);
  }
}

// The DownloadManager in the UI thread has provided a final name for the
// download specified by 'id'. Rename the in progress download, and remove it
// from our table if it has been completed or cancelled already.
// |need_delete_crdownload| indicates if we explicitly delete an intermediate
// .crdownload file or not.
//
// There are 3 possible rename cases where this method can be called:
// 1. tmp -> foo            (need_delete_crdownload=T)
// 2. foo.crdownload -> foo (need_delete_crdownload=F)
// 3. tmp-> Unconfirmed.xxx.crdownload (need_delete_crdownload=F)
void DownloadFileManager::OnFinalDownloadName(
    int id, const FilePath& full_path, bool need_delete_crdownload,
    DownloadManager* download_manager) {
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
           << " full_path = \"" << full_path.value() << "\""
           << " need_delete_crdownload = " << need_delete_crdownload;
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  DownloadFile* download = GetDownloadFile(id);
  if (!download)
    return;
  VLOG(20) << __FUNCTION__ << "()" << " download = " << download->DebugString();
  if (download->Rename(full_path, true /* is_final_rename */)) {
#if defined(OS_MACOSX)
    // Done here because we only want to do this once; see
    // http://crbug.com/13120 for details.
    download->AnnotateWithSourceInformation();
#endif
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(
            download_manager, &DownloadManager::DownloadRenamedToFinalName, id,
            full_path));
  } else {
    // Error. Between the time the UI thread generated 'full_path' to the time
    // this code runs, something happened that prevents us from renaming.
    CancelDownloadOnRename(id);
  }

  if (need_delete_crdownload)
    download->DeleteCrDownload();

  // If the download has completed before we got this final name, we remove it
  // from our in progress map.
  if (!download->in_progress()) {
    downloads_.erase(id);
    delete download;
  }

  if (downloads_.empty())
    StopUpdateTimer();
}

// Called only from OnFinalDownloadName or OnIntermediateDownloadName
// on the FILE thread.
void DownloadFileManager::CancelDownloadOnRename(int id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  DownloadFile* download = GetDownloadFile(id);
  if (!download)
    return;

  DownloadManager* download_manager = download->GetDownloadManager();
  if (!download_manager) {
    download->CancelDownloadRequest(resource_dispatcher_host_);
    return;
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(download_manager,
                        &DownloadManager::DownloadCancelled, id));
}
<commit_msg>Carnitas: Remove unneeded include from download_file_manager.cc<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_file_manager.h"

#include "base/file_util.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "net/base/io_buffer.h"

namespace {

// Throttle updates to the UI thread so that a fast moving download doesn't
// cause it to become unresponsive (in milliseconds).
const int kUpdatePeriodMs = 500;

DownloadManager* DownloadManagerForRenderViewHost(int render_process_id,
                                                  int render_view_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
                                                       render_view_id);
  if (contents) {
    Profile* profile = contents->profile();
    if (profile)
      return profile->GetDownloadManager();
  }

  return NULL;
}

}  // namespace

DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh)
    : next_id_(0),
      resource_dispatcher_host_(rdh) {
}

DownloadFileManager::~DownloadFileManager() {
  DCHECK(downloads_.empty());
}

void DownloadFileManager::Shutdown() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(this, &DownloadFileManager::OnShutdown));
}

void DownloadFileManager::OnShutdown() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  StopUpdateTimer();
  STLDeleteValues(&downloads_);
}

void DownloadFileManager::CreateDownloadFile(DownloadCreateInfo* info,
                                             DownloadManager* download_manager,
                                             bool get_hash) {
  VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  scoped_ptr<DownloadFile>
      download_file(new DownloadFile(info, download_manager));
  if (!download_file->Initialize(get_hash)) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableFunction(&download_util::CancelDownloadRequest,
                            resource_dispatcher_host_,
                            info->child_id,
                            info->request_id));
    delete info;
    return;
  }

  DCHECK(GetDownloadFile(info->download_id) == NULL);
  downloads_[info->download_id] = download_file.release();
  // TODO(phajdan.jr): fix the duplication of path info below.
  info->path = info->save_info.file_path;

  // The file is now ready, we can un-pause the request and start saving data.
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest,
                        info->child_id, info->request_id));

  StartUpdateTimer();

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(download_manager,
                        &DownloadManager::StartDownload, info));
}

void DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // This balances the pause in DownloadResourceHandler::OnResponseStarted.
  resource_dispatcher_host_->PauseRequest(child_id, request_id, false);
}

DownloadFile* DownloadFileManager::GetDownloadFile(int id) {
  DownloadFileMap::iterator it = downloads_.find(id);
  return it == downloads_.end() ? NULL : it->second;
}

void DownloadFileManager::StartUpdateTimer() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  if (!update_timer_.IsRunning()) {
    update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
                        this, &DownloadFileManager::UpdateInProgressDownloads);
  }
}

void DownloadFileManager::StopUpdateTimer() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  update_timer_.Stop();
}

void DownloadFileManager::UpdateInProgressDownloads() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  for (DownloadFileMap::iterator i = downloads_.begin();
       i != downloads_.end(); ++i) {
    int id = i->first;
    DownloadFile* download_file = i->second;
    DownloadManager* manager = download_file->GetDownloadManager();
    if (manager) {
      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(manager, &DownloadManager::UpdateDownload,
                            id, download_file->bytes_so_far()));
    }
  }
}

// Called on the IO thread once the ResourceDispatcherHost has decided that a
// request is a download.
int DownloadFileManager::GetNextId() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  return next_id_++;
}

void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(info);

  DownloadManager* manager = DownloadManagerForRenderViewHost(
      info->child_id, info->render_view_id);
  if (!manager) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableFunction(&download_util::CancelDownloadRequest,
                            resource_dispatcher_host_,
                            info->child_id,
                            info->request_id));
    delete info;
    return;
  }

  manager->CreateDownloadItem(info);

  bool hash_needed = resource_dispatcher_host_->safe_browsing_service()->
      DownloadBinHashNeeded();

  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
                        info, make_scoped_refptr(manager), hash_needed));
}

// We don't forward an update to the UI thread here, since we want to throttle
// the UI update rate via a periodic timer. If the user has cancelled the
// download (in the UI thread), we may receive a few more updates before the IO
// thread gets the cancel message: we just delete the data since the
// DownloadFile has been deleted.
void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  std::vector<DownloadBuffer::Contents> contents;
  {
    base::AutoLock auto_lock(buffer->lock);
    contents.swap(buffer->contents);
  }

  DownloadFile* download = GetDownloadFile(id);
  for (size_t i = 0; i < contents.size(); ++i) {
    net::IOBuffer* data = contents[i].first;
    const int data_len = contents[i].second;
    if (download)
      download->AppendDataToFile(data->data(), data_len);
    data->Release();
  }
}

void DownloadFileManager::OnResponseCompleted(int id, DownloadBuffer* buffer) {
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  delete buffer;
  DownloadFileMap::iterator it = downloads_.find(id);
  if (it != downloads_.end()) {
    DownloadFile* download = it->second;
    download->Finish();

    DownloadManager* download_manager = download->GetDownloadManager();
    if (download_manager) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(
              download_manager, &DownloadManager::OnAllDataSaved,
              id, download->bytes_so_far()));
    }

    // We need to keep the download around until the UI thread has finalized
    // the name.
    if (download->path_renamed()) {
      downloads_.erase(it);
      delete download;
    }
  }

  if (downloads_.empty())
    StopUpdateTimer();
}

// This method will be sent via a user action, or shutdown on the UI thread, and
// run on the download thread. Since this message has been sent from the UI
// thread, the download may have already completed and won't exist in our map.
void DownloadFileManager::CancelDownload(int id) {
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id;
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  DownloadFileMap::iterator it = downloads_.find(id);
  if (it != downloads_.end()) {
    DownloadFile* download = it->second;
    VLOG(20) << __FUNCTION__ << "()"
             << " download = " << download->DebugString();
    download->Cancel();

    if (download->path_renamed()) {
      downloads_.erase(it);
      delete download;
    }
  }

  if (downloads_.empty())
    StopUpdateTimer();
}

void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  DCHECK(manager);

  std::set<DownloadFile*> to_remove;

  for (DownloadFileMap::iterator i = downloads_.begin();
       i != downloads_.end(); ++i) {
    DownloadFile* download_file = i->second;
    if (download_file->GetDownloadManager() == manager) {
      download_file->CancelDownloadRequest(resource_dispatcher_host_);
      to_remove.insert(download_file);
    }
  }

  for (std::set<DownloadFile*>::iterator i = to_remove.begin();
       i != to_remove.end(); ++i) {
    downloads_.erase((*i)->id());
    delete *i;
  }
}

// Actions from the UI thread and run on the download thread

// The DownloadManager in the UI thread has provided an intermediate .crdownload
// name for the download specified by 'id'. Rename the in progress download.
void DownloadFileManager::OnIntermediateDownloadName(
    int id, const FilePath& full_path, DownloadManager* download_manager)
{
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
           << " full_path = \"" << full_path.value() << "\"";
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  DownloadFileMap::iterator it = downloads_.find(id);
  if (it == downloads_.end())
    return;

  DownloadFile* download = it->second;
  VLOG(20) << __FUNCTION__ << "()" << " download = " << download->DebugString();
  if (!download->Rename(full_path, false /* is_final_rename */)) {
    // Error. Between the time the UI thread generated 'full_path' to the time
    // this code runs, something happened that prevents us from renaming.
    CancelDownloadOnRename(id);
  }
}

// The DownloadManager in the UI thread has provided a final name for the
// download specified by 'id'. Rename the in progress download, and remove it
// from our table if it has been completed or cancelled already.
// |need_delete_crdownload| indicates if we explicitly delete an intermediate
// .crdownload file or not.
//
// There are 3 possible rename cases where this method can be called:
// 1. tmp -> foo            (need_delete_crdownload=T)
// 2. foo.crdownload -> foo (need_delete_crdownload=F)
// 3. tmp-> Unconfirmed.xxx.crdownload (need_delete_crdownload=F)
void DownloadFileManager::OnFinalDownloadName(
    int id, const FilePath& full_path, bool need_delete_crdownload,
    DownloadManager* download_manager) {
  VLOG(20) << __FUNCTION__ << "()" << " id = " << id
           << " full_path = \"" << full_path.value() << "\""
           << " need_delete_crdownload = " << need_delete_crdownload;
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  DownloadFile* download = GetDownloadFile(id);
  if (!download)
    return;
  VLOG(20) << __FUNCTION__ << "()" << " download = " << download->DebugString();
  if (download->Rename(full_path, true /* is_final_rename */)) {
#if defined(OS_MACOSX)
    // Done here because we only want to do this once; see
    // http://crbug.com/13120 for details.
    download->AnnotateWithSourceInformation();
#endif
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(
            download_manager, &DownloadManager::DownloadRenamedToFinalName, id,
            full_path));
  } else {
    // Error. Between the time the UI thread generated 'full_path' to the time
    // this code runs, something happened that prevents us from renaming.
    CancelDownloadOnRename(id);
  }

  if (need_delete_crdownload)
    download->DeleteCrDownload();

  // If the download has completed before we got this final name, we remove it
  // from our in progress map.
  if (!download->in_progress()) {
    downloads_.erase(id);
    delete download;
  }

  if (downloads_.empty())
    StopUpdateTimer();
}

// Called only from OnFinalDownloadName or OnIntermediateDownloadName
// on the FILE thread.
void DownloadFileManager::CancelDownloadOnRename(int id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  DownloadFile* download = GetDownloadFile(id);
  if (!download)
    return;

  DownloadManager* download_manager = download->GetDownloadManager();
  if (!download_manager) {
    download->CancelDownloadRequest(resource_dispatcher_host_);
    return;
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(download_manager,
                        &DownloadManager::DownloadCancelled, id));
}
<|endoftext|>


<commit_before>#include <errno.h>
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

string shell_prompt(); //prototype for prompt function
int cmd_interpreter(string); //prototype for command interpreter
void input_redir(vector<string>); //prototype for input redirection function
int input_helper(string, string);
void output_redir(vector<string>); //prototype for output redirection function
int output_helper(string, string);

int main (int argc, char** argv)
{
	while(true)
	{
		vector<string> inVector;
		string input;
		input = shell_prompt();
		//while (inVector.back() != "")
		if (input == "exit")
		{
			cout << "Exiting rshell." << endl;
			exit(0);
		}
		else
		{
			char_separator<char> sep(";", "|&#<>");
			string t;
			tokenizer< char_separator<char> > tokens(input, sep);
			BOOST_FOREACH(t, tokens)
			{
				//TODO do different things depending on delimiters in vector
				inVector.push_back(t);
			} //end BOOST_FOREACH

			bool comment_sentinel = true;
			bool pipe_sentinel = false;

			for (unsigned i = 0; i < inVector.size(); i++) //go through vector of commands - looking for comments
			{
				if(comment_sentinel)	//if a comment sign is not found, execute
				{
					string in = inVector.at(i);
			cerr << "[ " << in << " ]" << endl;
					if (in.at(0) == '#')
					{
						comment_sentinel = false;
					}

					else
					{
						for (unsigned k = 0; k < inVector.size(); k++)
						{

							if (inVector.at(k).at(0) == '&')
							{
								//TODO: remove later and fix
							}

							else if (inVector.at(k).at(0) == '|')
							{
								if (inVector.at(i + 1).at(0) == '|') //likely to go out of range if at end of command
								{
									pipe_sentinel = true;
								}
								if (pipe_sentinel)
								{
									//TODO: remove later and fix
								}

							}

							else if (inVector.at(k).at(0) == '<')
							{
								//input redirection
					//	cerr << "we indir i hope" << endl;
								input_redir(inVector);
								 //input_redir handles
								 comment_sentinel = false; //force a skip
								 break;
							}

							else if (inVector.at(k).at(0) == '>')
							{
								//output redirection
					//	cerr << "we outdir i hope" << endl;
								output_redir(inVector);
								 //output_redir function handles this
								 comment_sentinel = false; //force a skip
								 break;

							}
							else
							{
								; //nothing
								continue;
							}
						}
						cmd_interpreter(in);
					}
				}

				//TODO: this is for connectors
				// check if the current in.at(0) character equals a connector
				// if it does, check if the next one equals a connector
				// if it does, run both commands
				// check return values of both commands
				// ????
				// profit
			}//endfor
		}//endif
	}//endwhile

	return 0;
}

void input_redir(vector<string> input)
{
	//handles all of input redirection
	for (unsigned i = 0; i < input.size(); i++)
	{
		if (input.at(i).at(0) == '<')
		{
//	cerr << "we input now" << endl;
			input_helper(input.at(i-1), input.at(i+1));
		}
	}
}

int input_helper(string one, string two)
{
	int pid = fork();
	if (pid == 0)
	{
		//child
		//open close dup
		if (open(two.c_str(), O_RDONLY) != -1)
		{
			if(close(0) != -1) //stdin
			{
				if(dup(0) != -1)
				{
		//cerr << one << endl;
					cmd_interpreter(one);
					return 1;
				}
				else
				{
					perror("dup");
					exit(1);
				}
			}
			else
			{
				perror("close");
				exit(1);
			}
		}
		else
		{
			perror("open");
			exit(1);
		}
		if (close(0) == -1)
		{
			perror("close");
			exit(1);
		}
	}
	else
	{
		//parent
//		close(0);
		if (waitpid(-1, NULL, 0) == -1)
		{
			perror("waitpid");
			exit(1);
		}
		if(close(0) == -1)
		{
			perror("close");
			exit(1);
		}
		return 1;
	}

	return 0;
}

void output_redir(vector<string> input)
{
	//handles all output redirection
	for (unsigned i = 0; i < input.size(); i++)
	{
		//iterate through vector and finds redirection
		if (input.at(i).at(0) == '>')
		{
//		cerr << "we output now" << endl;
			output_helper(input.at(i-1), input.at(i+1));
		}
	}
}

int output_helper(string one, string two)
{
cerr << one << " " << two << endl;
	int pid = fork();
	if (pid == 0)
	{
		//child
		//open close dup
		if (open(two.c_str(), O_WRONLY | O_CREAT) != -1)
		{
			if(close(1) != -1) //stdin
			{
				if(dup(1) != -1)
				{
					cmd_interpreter(one);
					return 1;
				}
				else
				{
					perror("dup");
					exit(1);
				}
			}
			else
			{
				perror("close");
				exit(1);
			}
		}
		else
		{
			perror("open");
			exit(1);
		}
		if (close(1) == -1)
		{
			perror("close");
			exit(1);
		}
	}
	else
	{
		//parent
//		close(1);
		if (waitpid(-1, NULL, 0) == -1)
		{
			perror("waitpid");
			exit(1);
		}
		if (close(1) == -1)
		{
			perror("close");
			exit(1);
		}
		return 1;
	}

	return 0;
}

int cmd_interpreter(string input)//, char** argv)
{
	//parse command to seperate command and parameters

	//int len = input.length();

	vector<string> invector;
	string t;
	char_separator<char> sep(" ");
	tokenizer< char_separator<char> > tokens(input, sep);
	//int i = 0;
	BOOST_FOREACH(t, tokens)		//tokenize input string with flags to seperate items
	{
		invector.push_back(t);
	}
	unsigned len = invector.size();

	const char** cinput = new const char*[len+2];
	const char* program = invector.at(0).c_str();

	cinput[0] = program;

	for(unsigned i = 1; i < 1 + len; i++)
	{
		cinput[i] = invector[i].c_str();
	}
	cinput[len] = '\0';

//	int pipefd[
	int pid = fork();
	if(pid == 0)
	{
		if (execvp(program, (char**)cinput) == -1)
		{
			perror("execvp"); // throw an error
			exit(1);
		}
		else
		{
			return 1;
		}
	}
	else
	{
		//append stuff here

		//parent wait
		if (waitpid(-1, NULL, 0) == -1)
		{
			perror("waitpid");
			exit(1);
		}
	}

	return 0;
}

string shell_prompt()
{
	string in;
	//TODO - error checking for getlogin and gethostname
	//implement later
//	struct utsname name;
//	errno = 0;

//	uname(&name)
	/*
	char name[256];
	int maxlen = 64;
	if (!gethostname(name, maxlen))
	{
		string strname(name);
		cout << getlogin() << "@" << name  << "$ "; //custom prompt with hostname and login name
		cin >> in;
	}
	else
	{
		perror("gethostname"); //throw error if not found
	}
	*/
	cout << "rshell$ ";
	getline(cin, in);
	cin.clear();
	return in;
}
<commit_msg>create a change<commit_after>#include <errno.h>
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

string shell_prompt(); //prototype for prompt function
int cmd_interpreter(string); //prototype for command interpreter
void input_redir(vector<string>); //prototype for input redirection function
int input_helper(string, string);
void output_redir(vector<string>); //prototype for output redirection function
int output_helper(string, string);

int main (int argc, char** argv)
{
	while(true)
	{
		vector<string> inVector;
		string input;
		input = shell_prompt();
		//while (inVector.back() != "")
		if (input == "exit")
		{
			cout << "Exiting rshell." << endl;
			exit(0);
		}
		else
		{
			char_separator<char> sep(";", "|&#<>");
			string t;
			tokenizer< char_separator<char> > tokens(input, sep);
			BOOST_FOREACH(t, tokens)
			{
				//TODO do different things depending on delimiters in vector
				inVector.push_back(t);
			} //end BOOST_FOREACH

			bool comment_sentinel = true;
			bool pipe_sentinel = false;

			for (unsigned i = 0; i < inVector.size(); i++) //go through vector of commands - looking for comments
			{
				if(comment_sentinel)	//if a comment sign is not found, execute
				{
					string in = inVector.at(i);
			cerr << "[ " << in << " ]" << endl;
					if (in.at(0) == '#')
					{
						comment_sentinel = false;
					}

					else
					{
						for (unsigned k = 0; k < inVector.size(); k++)
						{

							if (inVector.at(k).at(0) == '&')
							{
								//TODO: remove later and fix
							}

							else if (inVector.at(k).at(0) == '|')
							{
								if (inVector.at(i + 1).at(0) == '|') //likely to go out of range if at end of command
								{
									pipe_sentinel = true;
								}
								if (pipe_sentinel)
								{
									//TODO: remove later and fix
								}

							}

							else if (inVector.at(k).at(0) == '<')
							{
								//input redirection
					//	cerr << "we indir i hope" << endl;
								input_redir(inVector);
								 //input_redir handles
								 comment_sentinel = false; //force a skip
								 break;
							}

							else if (inVector.at(k).at(0) == '>')
							{
								//output redirection
					//	cerr << "we outdir i hope" << endl;
								output_redir(inVector);
								 //output_redir function handles this
								 comment_sentinel = false; //force a skip
								 break;

							}
							else
							{
								; //nothing
								continue;
							}
						}
						cmd_interpreter(in);
					}
				}

				//TODO: this is for connectors
				// check if the current in.at(0) character equals a connector
				// if it does, check if the next one equals a connector
				// if it does, run both commands
				// check return values of both commands
				// ????
				// profit
			}//endfor
		}//endif
	}//endwhile

	return 0;
}

void input_redir(vector<string> input)
{
	//handles all of input redirection
	for (unsigned i = 0; i < input.size(); i++)
	{
		if (input.at(i).at(0) == '<')
		{
//	cerr << "we input now" << endl;
			input_helper(input.at(i-1), input.at(i+1));
		}
	}
}

int input_helper(string one, string two)
{
	int pid = fork();
	if (pid == 0)
	{
		//child
		//open close dup
		if (open(two.c_str(), O_RDONLY) != -1)
		{
			if(close(0) != -1) //stdin
			{
				if(dup(0) != -1)
				{
		//cerr << one << endl;
					cmd_interpreter(one);
					return 1;
				}
				else
				{
					perror("dup");
					exit(1);
				}
			}
			else
			{
				perror("close");
				exit(1);
			}
		}
		else
		{
			perror("open");
			exit(1);
		}
		if (close(0) == -1)
		{
			perror("close");
			exit(1);
		}
	}
	else
	{
		//parent
//		close(0);
		if (waitpid(-1, NULL, 0) == -1)
		{
			perror("waitpid");
			exit(1);
		}
		if(close(0) == -1)
		{
			perror("close");
			exit(1);
		}
		return 1;
	}

	return 0;
}

void output_redir(vector<string> input)
{
	//handles all output redirection
	for (unsigned i = 0; i < input.size(); i++)
	{
		//iterate through vector and finds redirection
		if (input.at(i).at(0) == '>')
		{
//		cerr << "we output now" << endl;
			output_helper(input.at(i-1), input.at(i+1));
		}
	}
}

int output_helper(string one, string two)
{
cerr << one << " " << two << endl;
	int pid = fork();
	if (pid == 0)
	{
		//child
		//open close dup
		if (open(two.c_str(), O_WRONLY | O_CREAT) != -1)
		{
			if(close(1) != -1) //stdin
			{
				if(dup(1) != -1)
				{
					cmd_interpreter(one);
					return 1;
				}
				else
				{
					perror("dup");
					exit(1);
				}
			}
			else
			{
				perror("close");
				exit(1);
			}
		}
		else
		{
			perror("open");
			exit(1);
		}
		if (close(1) == -1)
		{
			perror("close");
			exit(1);
		}
	}
	else
	{
		//parent
//		close(1);
		if (waitpid(-1, NULL, 0) == -1)
		{
			perror("waitpid");
			exit(1);
		}
		if (close(1) == -1)
		{
			perror("close");
			exit(1);
		}
		return 1;
	}

	return 0;
}

int cmd_interpreter(string input)//, char** argv)
{
	//parse command to seperate command and parameters

	//int len = input.length();

	vector<string> invector;
	string t;
	char_separator<char> sep(" ");
	tokenizer< char_separator<char> > tokens(input, sep);
	//int i = 0;
	BOOST_FOREACH(t, tokens)		//tokenize input string with flags to seperate items
	{
		invector.push_back(t);
	}
	unsigned len = invector.size();

	const char** cinput = new const char*[len+2];
	const char* program = invector.at(0).c_str();

	cinput[0] = program;

	for(unsigned i = 1; i < 1 + len; i++)
	{
		cinput[i] = invector[i].c_str();
	}
	cinput[len] = '\0';

//	int pipefd[
	int pid = fork();
	if(pid == 0)
	{
		if (execvp(program, (char**)cinput) == -1)
		{
			perror("execvp"); // throw an error
			exit(1);
		}
		else
		{
			return 1;
		}
	}
	else
	{
		//append stuff here

		//parent wait
		if (waitpid(-1, NULL, 0) == -1)
		{
			perror("waitpid");
			exit(1);
		}
	}

	return 0;
}

string shell_prompt()
{
	string in;
	//TODO - error checking for getlogin and gethostname
	//implement later
//	struct utsname name;
//	errno = 0;
//	uname(&name)
	/*
	char name[256];
	int maxlen = 64;
	if (!gethostname(name, maxlen))
	{
		string strname(name);
		cout << getlogin() << "@" << name  << "$ "; //custom prompt with hostname and login name
		cin >> in;
	}
	else
	{
		perror("gethostname"); //throw error if not found
	}
	*/
	cout << "rshell$ ";
	getline(cin, in);
	cin.clear();
	return in;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "base/scoped_temp_dir.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

#if !defined(OS_MACOSX)
// TODO(port): BUG16322
static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("save_page");

static const char* kAppendedExtension =
#if defined(OS_WIN)
    ".htm";
#else
    ".html";
#endif

#endif  // !defined(OS_MACOSX)

namespace {

class SavePageFinishedObserver : public NotificationObserver {
 public:
  SavePageFinishedObserver() {
    registrar_.Add(this, NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
                   NotificationService::AllSources());
    ui_test_utils::RunMessageLoop();
  }

  GURL page_url() const { return page_url_; }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED) {
      page_url_ = *Details<GURL>(details).ptr();
      MessageLoopForUI::current()->Quit();
    } else {
      NOTREACHED();
    }
  }

 private:
  NotificationRegistrar registrar_;

  GURL page_url_;

  DISALLOW_COPY_AND_ASSIGN(SavePageFinishedObserver);
};

class SavePageBrowserTest : public InProcessBrowserTest {
 protected:
  void SetUp() {
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
    ASSERT_TRUE(save_dir_.CreateUniqueTempDir());
    InProcessBrowserTest::SetUp();
  }

  // Path to directory containing test data.
  FilePath test_dir_;

  // Temporary directory we will save pages to.
  ScopedTempDir save_dir_;
};

#if !defined(OS_MACOSX)
// TODO(port): BUG16322
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnly) {
  FilePath file_name(FILE_PATH_LITERAL("a.htm"));
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_TRUE(current_tab);

  FilePath full_file_name = save_dir_.path().Append(file_name);
  FilePath dir = save_dir_.path().AppendASCII("a_files");
  ASSERT_TRUE(current_tab->SavePage(full_file_name, dir,
                                    SavePackage::SAVE_AS_ONLY_HTML));

  SavePageFinishedObserver observer;

  EXPECT_EQ(url, observer.page_url());
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(file_util::PathExists(full_file_name));
  EXPECT_FALSE(file_util::PathExists(dir));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).Append(file_name),
      full_file_name));
}

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveCompleteHTML) {
  FilePath file_name(FILE_PATH_LITERAL("b.htm"));
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_TRUE(current_tab);

  FilePath full_file_name = save_dir_.path().Append(file_name);
  FilePath dir = save_dir_.path().AppendASCII("b_files");
  ASSERT_TRUE(current_tab->SavePage(full_file_name, dir,
                                    SavePackage::SAVE_AS_COMPLETE_HTML));

  SavePageFinishedObserver observer;

  EXPECT_EQ(url, observer.page_url());
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(file_util::PathExists(full_file_name));
  EXPECT_TRUE(file_util::PathExists(dir));
  EXPECT_TRUE(file_util::TextContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("b.saved1.htm"),
      full_file_name));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.png"),
      dir.AppendASCII("1.png")));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.css"),
      dir.AppendASCII("1.css")));
}
#endif  // !defined(OS_MACOSX)

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) {
  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kAboutBlankURL));
  ASSERT_TRUE(browser()->command_updater()->SupportsCommand(IDC_SAVE_PAGE));
  EXPECT_FALSE(browser()->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE));
}

#if !defined(OS_MACOSX)
// TODO(port): BUG16322
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, FileNameFromPageTitle) {
  FilePath file_name(FILE_PATH_LITERAL("b.htm"));

  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  FilePath full_file_name = save_dir_.path().AppendASCII(
      std::string("Test page for saving page feature") + kAppendedExtension);
  FilePath dir = save_dir_.path().AppendASCII(
      "Test page for saving page feature_files");

  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_TRUE(current_tab);

  ASSERT_TRUE(current_tab->SavePage(full_file_name, dir,
                                    SavePackage::SAVE_AS_COMPLETE_HTML));
  SavePageFinishedObserver observer;

  EXPECT_EQ(url, observer.page_url());
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(file_util::PathExists(full_file_name));
  EXPECT_TRUE(file_util::PathExists(dir));
  EXPECT_TRUE(file_util::TextContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("b.saved2.htm"),
      full_file_name));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.png"),
      dir.AppendASCII("1.png")));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.css"),
      dir.AppendASCII("1.css")));
}
#endif  // !defined(OS_MACOSX)

}  // namespace
<commit_msg>Enable browser_tests: SavePageBrowserTest.FileNameFromPageTitle & SavePageBrowserTest.SaveHTMLOnly on the Mac.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "base/scoped_temp_dir.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("save_page");

static const char* kAppendedExtension =
#if defined(OS_WIN)
    ".htm";
#else
    ".html";
#endif

namespace {

class SavePageFinishedObserver : public NotificationObserver {
 public:
  SavePageFinishedObserver() {
    registrar_.Add(this, NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
                   NotificationService::AllSources());
    ui_test_utils::RunMessageLoop();
  }

  GURL page_url() const { return page_url_; }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED) {
      page_url_ = *Details<GURL>(details).ptr();
      MessageLoopForUI::current()->Quit();
    } else {
      NOTREACHED();
    }
  }

 private:
  NotificationRegistrar registrar_;

  GURL page_url_;

  DISALLOW_COPY_AND_ASSIGN(SavePageFinishedObserver);
};

class SavePageBrowserTest : public InProcessBrowserTest {
 protected:
  void SetUp() {
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
    ASSERT_TRUE(save_dir_.CreateUniqueTempDir());
    InProcessBrowserTest::SetUp();
  }

  // Path to directory containing test data.
  FilePath test_dir_;

  // Temporary directory we will save pages to.
  ScopedTempDir save_dir_;
};

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnly) {
  FilePath file_name(FILE_PATH_LITERAL("a.htm"));
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_TRUE(current_tab);

  FilePath full_file_name = save_dir_.path().Append(file_name);
  FilePath dir = save_dir_.path().AppendASCII("a_files");
  ASSERT_TRUE(current_tab->SavePage(full_file_name, dir,
                                    SavePackage::SAVE_AS_ONLY_HTML));

  SavePageFinishedObserver observer;

  EXPECT_EQ(url, observer.page_url());
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(file_util::PathExists(full_file_name));
  EXPECT_FALSE(file_util::PathExists(dir));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).Append(file_name),
      full_file_name));
}

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveCompleteHTML) {
  FilePath file_name(FILE_PATH_LITERAL("b.htm"));
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_TRUE(current_tab);

  FilePath full_file_name = save_dir_.path().Append(file_name);
  FilePath dir = save_dir_.path().AppendASCII("b_files");
  ASSERT_TRUE(current_tab->SavePage(full_file_name, dir,
                                    SavePackage::SAVE_AS_COMPLETE_HTML));

  SavePageFinishedObserver observer;

  EXPECT_EQ(url, observer.page_url());
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(file_util::PathExists(full_file_name));
  EXPECT_TRUE(file_util::PathExists(dir));
  EXPECT_TRUE(file_util::TextContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("b.saved1.htm"),
      full_file_name));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.png"),
      dir.AppendASCII("1.png")));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.css"),
      dir.AppendASCII("1.css")));
}

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) {
  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kAboutBlankURL));
  ASSERT_TRUE(browser()->command_updater()->SupportsCommand(IDC_SAVE_PAGE));
  EXPECT_FALSE(browser()->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE));
}

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, FileNameFromPageTitle) {
  FilePath file_name(FILE_PATH_LITERAL("b.htm"));

  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  FilePath full_file_name = save_dir_.path().AppendASCII(
      std::string("Test page for saving page feature") + kAppendedExtension);
  FilePath dir = save_dir_.path().AppendASCII(
      "Test page for saving page feature_files");

  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_TRUE(current_tab);

  ASSERT_TRUE(current_tab->SavePage(full_file_name, dir,
                                    SavePackage::SAVE_AS_COMPLETE_HTML));
  SavePageFinishedObserver observer;

  EXPECT_EQ(url, observer.page_url());
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(file_util::PathExists(full_file_name));
  EXPECT_TRUE(file_util::PathExists(dir));
  EXPECT_TRUE(file_util::TextContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("b.saved2.htm"),
      full_file_name));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.png"),
      dir.AppendASCII("1.png")));
  EXPECT_TRUE(file_util::ContentsEqual(
      test_dir_.Append(FilePath(kTestDir)).AppendASCII("1.css"),
      dir.AppendASCII("1.css")));
}

}  // namespace
<|endoftext|>


<commit_before>#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "MuMaterial.h"
#include "counter_point.hpp"

using namespace std;

void ValidateArguments (int argc, char* argv[]);
void PrintVector (vector<int> v, string message);
vector<int> GetHarmonicRange (int note_pitch);
vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs);
vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs);

int main (int argc, char* argv[])
{
    // ValidateArguments(argc, argv);

    // string output_path = argc > 2 ? argv[2] : "./";
    // string score_file_path = argv[1];

    // MuInit();
    // MuMaterial material;
    // material.LoadScore(argv[1]);

    // material.SetDefaultFunctionTables();
    // material.Score(output_path + "score");
    // material.Orchestra(output_path + "orchestra");

    MuNote note;
    MuMaterial material;

    note.SetPitch(60);
    material += note;

    note.SetPitch(62);
    material += note;

    note.SetPitch(64);
    material += note;

    CounterPoint counter_point(material);
    counter_point.PrintHarmonicPitchs();

    return 0;
}

void ValidateArguments (int argc, char* argv[])
{
    bool has_arguments = argc < 2;
    if (has_arguments)
    {
        cout << "Usage: " << argv[0] << " [score_file_path] [output_path]" << endl;
        exit(-1);
    }
}

void PrintVector (vector<int> v, string message)
{
    cout << message << ": ";
    for (unsigned int index = 0; index < v.size(); index++)
    {
        cout << v[index] << " ";
    }
    cout << endl;
}

vector<int> GetHarmonicRange (int note_pitch)
{
    int unison = note_pitch;
    int third_minor = note_pitch - 3;
    int third_major = note_pitch - 4;
    int fifith_perfect = note_pitch - 7;
    int sixth_minor = note_pitch - 8;
    int sixth_major = note_pitch - 9;

    vector<int> harmonic_range {unison, third_minor, third_major,
                                  fifith_perfect, sixth_minor, sixth_major};

    return harmonic_range;
}

vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs)
{
    scale_pitch = scale_pitch % 12;

    vector<int> scale_pitchs = { 0 + scale_pitch, 2 + scale_pitch,
                                 4 + scale_pitch, 5 + scale_pitch,
                                 7 + scale_pitch, 9 + scale_pitch,
                                 11 + scale_pitch };

    vector<int> pitchs_on_scale;

    for (unsigned int index = 0; index < pitchs.size(); index++)
    {
        int pitch = pitchs[index] % 12;
        bool found_pitch = find(scale_pitchs.begin(), scale_pitchs.end(),
                                pitch) != scale_pitchs.end();

        if(found_pitch)
        {
            pitchs_on_scale.push_back(pitchs[index]);
        }
    }

    return pitchs_on_scale;
}

vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs)
{
    vector<int> pitchs_without_unison = pitchs;

    pitchs_without_unison.erase(remove(pitchs_without_unison.begin(),
                                       pitchs_without_unison.end(),
                                       unison_pitch),
                                pitchs_without_unison.end());

    return pitchs_without_unison;
}
<commit_msg>Back main.cpp to load file<commit_after>#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "MuMaterial.h"
#include "counter_point.hpp"

using namespace std;

void ValidateArguments (int argc, char* argv[]);
void PrintVector (vector<int> v, string message);
vector<int> GetHarmonicRange (int note_pitch);
vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs);
vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs);

int main (int argc, char* argv[])
{
    ValidateArguments(argc, argv);

    string output_path = argc > 2 ? argv[2] : "./";
    string score_file_path = argv[1];

    MuInit();
    MuMaterial material;
    material.LoadScore(argv[1]);

    CounterPoint counter_point(material);
    counter_point.SetScalePitch(60);
    counter_point.PrintHarmonicPitchs();

    material.SetDefaultFunctionTables();
    material.Score(output_path + "score");
    material.Orchestra(output_path + "orchestra");

    // MuNote note;
    // MuMaterial material;

    // note.SetPitch(60);
    // material += note;

    // note.SetPitch(62);
    // material += note;

    // note.SetPitch(64);
    // material += note;

    // CounterPoint counter_point(material);
    // counter_point.PrintHarmonicPitchs();

    return 0;
}

void ValidateArguments (int argc, char* argv[])
{
    bool has_arguments = argc < 2;
    if (has_arguments)
    {
        cout << "Usage: " << argv[0] << " [score_file_path] [output_path]" << endl;
        exit(-1);
    }
}

void PrintVector (vector<int> v, string message)
{
    cout << message << ": ";
    for (unsigned int index = 0; index < v.size(); index++)
    {
        cout << v[index] << " ";
    }
    cout << endl;
}

vector<int> GetHarmonicRange (int note_pitch)
{
    int unison = note_pitch;
    int third_minor = note_pitch - 3;
    int third_major = note_pitch - 4;
    int fifith_perfect = note_pitch - 7;
    int sixth_minor = note_pitch - 8;
    int sixth_major = note_pitch - 9;

    vector<int> harmonic_range {unison, third_minor, third_major,
                                  fifith_perfect, sixth_minor, sixth_major};

    return harmonic_range;
}

vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs)
{
    scale_pitch = scale_pitch % 12;

    vector<int> scale_pitchs = { 0 + scale_pitch, 2 + scale_pitch,
                                 4 + scale_pitch, 5 + scale_pitch,
                                 7 + scale_pitch, 9 + scale_pitch,
                                 11 + scale_pitch };

    vector<int> pitchs_on_scale;

    for (unsigned int index = 0; index < pitchs.size(); index++)
    {
        int pitch = pitchs[index] % 12;
        bool found_pitch = find(scale_pitchs.begin(), scale_pitchs.end(),
                                pitch) != scale_pitchs.end();

        if(found_pitch)
        {
            pitchs_on_scale.push_back(pitchs[index]);
        }
    }

    return pitchs_on_scale;
}

vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs)
{
    vector<int> pitchs_without_unison = pitchs;

    pitchs_without_unison.erase(remove(pitchs_without_unison.begin(),
                                       pitchs_without_unison.end(),
                                       unison_pitch),
                                pitchs_without_unison.end());

    return pitchs_without_unison;
}
<|endoftext|>


<commit_before>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Cyvasse Online is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include <fstream>
#include <iostream>
#include <string>
#include <tnt/tntconfig.h>
#include <tnt/tntnet.h>
#include <cxxtools/log.h>
#include <yaml-cpp/yaml.h>

using namespace std;

int main()
{
	log_init("log.xml");

	auto config = YAML::LoadFile("config.yml");
	auto listenPort = config["listenPort"].as<int>();
	auto staticDir  = config["staticDir"].as<string>();

	try
	{
		tnt::Tntnet app;

		app.listen(listenPort);
		app.setAppName("cyvasse-online");

		// setArg() and setting the documentRoot per
		// mapping require the git version of tntnet

		// static files
		app.mapUrl("^/(.+)$",                    "static@tntnet").setPathInfo("$1")
			.setArg("documentRoot", staticDir);
		app.mapUrl("^/css/(.+)$",                "static@tntnet").setPathInfo("$1")
			.setArg("documentRoot", "resources/css");

		// non-page dynamic content
		app.mapUrl("^/random-matches$", "random-game-view");

		// pages
		app.mapUrl("^/$",                            "page"  ).setArg("content", "index");
		app.mapUrl("^/index(\\.json)?$",             "page$1").setArg("content", "index");
		app.mapUrl("^/index\\.htm(l)?$",             "page"  ).setArg("content", "index");
		app.mapUrl("^/legal$",                       "page"  ).setArg("content", "legal");
		app.mapUrl("^/match/.{4}(\\.json)?$",        "page$1").setArg("content", "game");
		app.mapUrl("^/rule_sets/([^.]+)(\\.json)?$", "page$2").setArg("content", "rule-set").setArg("name", "$1");
		// 404 if nothing matched
		app.mapUrl(".*",                             "page"  ).setArg("content", "404");

		app.run();
	}
	catch(exception& e)
	{
		cerr << e.what() << endl;
		return 1;
	}

	return 0;
}
<commit_msg>Automatically write .pid-file<commit_after>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Cyvasse Online is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include <fstream>
#include <iostream>
#include <string>
#include <csignal>
#include <cstdio>

#include <unistd.h>
#include <tnt/tntconfig.h>
#include <tnt/tntnet.h>
#include <cxxtools/log.h>
#include <yaml-cpp/yaml.h>

using namespace std;

static constexpr const char* pidFileName = "cyvasse-online.pid";

void createPidFile();
void removePidFile();
void setupSignals();

int main()
{
	setupSignals();

	log_init("log.xml");

	auto config = YAML::LoadFile("config.yml");
	auto listenPort = config["listenPort"].as<int>();
	auto staticDir  = config["staticDir"].as<string>();

	int retVal = 0;

	try
	{
		createPidFile();

		tnt::Tntnet app;

		app.listen(listenPort);
		app.setAppName("cyvasse-online");

		// setArg() and setting the documentRoot per
		// mapping require the git version of tntnet

		// static files
		app.mapUrl("^/(.+)$",                    "static@tntnet").setPathInfo("$1")
			.setArg("documentRoot", staticDir);
		app.mapUrl("^/css/(.+)$",                "static@tntnet").setPathInfo("$1")
			.setArg("documentRoot", "resources/css");

		// non-page dynamic content
		app.mapUrl("^/random-matches$", "random-game-view");

		// pages
		app.mapUrl("^/$",                            "page"  ).setArg("content", "index");
		app.mapUrl("^/index(\\.json)?$",             "page$1").setArg("content", "index");
		app.mapUrl("^/index\\.htm(l)?$",             "page"  ).setArg("content", "index");
		app.mapUrl("^/legal$",                       "page"  ).setArg("content", "legal");
		app.mapUrl("^/match/.{4}(\\.json)?$",        "page$1").setArg("content", "game");
		app.mapUrl("^/rule_sets/([^.]+)(\\.json)?$", "page$2").setArg("content", "rule-set").setArg("name", "$1");
		// 404 if nothing matched
		app.mapUrl(".*",                             "page"  ).setArg("content", "404");

		app.run();
	}
	catch(exception& e)
	{
		cerr << e.what() << endl;
		retVal = 1;
	}

	removePidFile();
	return retVal;
}

void createPidFile()
{
	ofstream pidFile(pidFileName);
	if(pidFile)
	{
		pidFile << getpid();
		pidFile.close();
	}
}

void removePidFile()
{
	remove(pidFileName);
}

extern "C" void stopWebapp(int /* signal */)
{
	removePidFile();
	exit(0);
}

void setupSignals()
{
#ifdef HAVE_SIGACTION
	struct sigaction newAction, oldAction;

	// setup sigaction struct for stopWebapp
	newAction.sa_handler = stopWebapp;
	sigemptyset(&newAction.sa_mask);
	newAction.sa_flags = 0;

	sigaction(SIGHUP, nullptr, &oldAction);
	if(oldAction.sa_handler != SIG_IGN)
		sigaction(SIGHUP, &newAction, nullptr);

	sigaction(SIGINT, nullptr, &oldAction);
	if(oldAction.sa_handler != SIG_IGN)
		sigaction(SIGINT, &newAction, nullptr);

	sigaction(SIGTERM, nullptr, &oldAction);
	if(oldAction.sa_handler != SIG_IGN)
		sigaction(SIGTERM, &newAction, nullptr);
#else
	if(signal(SIGHUP, stopWebapp) == SIG_IGN)
		signal(SIGHUP, SIG_IGN);

	if(signal(SIGINT, stopWebapp) == SIG_IGN)
		signal(SIGINT, SIG_IGN);

	if(signal(SIGTERM, stopWebapp) == SIG_IGN)
		signal(SIGTERM, SIG_IGN);
#endif
}
<|endoftext|>


<commit_before>#include <iostream>
#include "main.hpp"
#include "system/printer.hpp"

#ifndef OBJ_PATH
#define OBJ_PATH "share/cube.obj"
#endif
#ifndef MTL_PATH
#define MTL_PATH "share/cube.mtl"
#endif
#ifndef VERT_PATH
#define VERT_PATH "share/fallback.vert"
#endif
#ifndef FRAG_PATH
#define FRAG_PATH "share/shade.frag"
#endif

void printErrors(void) {}

template<typename T1, typename... TN>
void printErrors(T1 &t1, TN &... tn) {
	for(auto e : t1) {
		std::cout << e << std::endl;
	}
	printErrors(tn...);
}

int main(int argc, const char **argv) {
	using namespace Util;
	if(glfwInit() == 0) {
		std::cout << "Failed to initialize GLFW "
			<< glfwGetVersionString() << std::endl;
		return 1;
	}

	const char *obj_fname, *mtl_fname, *vert_fname, *frag_fname;

	if(argc >= 2) obj_fname = argv[1];
	else obj_fname = OBJ_PATH;
	if(argc >= 3) mtl_fname = argv[2];
	else mtl_fname = MTL_PATH;
	if(argc >= 4) vert_fname = argv[3];
	else vert_fname = VERT_PATH;
	if(argc >= 5) frag_fname = argv[4];
	else frag_fname = FRAG_PATH;

	std::atomic_bool alive(true);
	Control::control ctl(alive, obj_fname);
	if(!alive) {
		std::cout << "Control construction failed." << std::endl;
		printErrors(ctl.viewer.errors, ctl.errors);
		return 1;
	}
	if(!ctl.viewer.setProg(alive, vert_fname, frag_fname)) {
		std::cout << "Failed to compile or link shaders." << std::endl;
		std::cout << "For shaders " << vert_fname << ", "
			<< frag_fname << std::endl;
		printErrors(ctl.viewer.errors, ctl.errors);
		return 1;
	} else {
		using namespace System;
		Printer<6> printer;
		std::string cols[]{"GLFW", "OpenGL", "Path"},
			rows[]{"", "Major", "Minor", "Revision", "",
				"", "Wavefront obj", "Wavefront mtl",
				"Vertex shader", "Fragment shader", ""},
			paths[]{obj_fname, mtl_fname, vert_fname, frag_fname};
		int versions[6]{0};
		glfwGetVersion(&versions[0], &versions[2], &versions[4]);
		glGetIntegerv(GL_MAJOR_VERSION, &versions[1]);
		glGetIntegerv(GL_MINOR_VERSION, &versions[3]);
		printer.push(&rows[0], &rows[5]).level()
			.push<int, 3, 2>(versions, &cols[0], &cols[2]).level()
			.insert(0, Printer_Base::repeat(3)).level()
			.push(&rows[5], &rows[5]+6).level()
			.push<std::string, 4, 1, 31>(paths, &cols[2], &cols[3]+1).level();
		std::cout << printer << std::endl;

		if(!task::init(alive, &ctl)) {
			std::cout << "Control Initialization failed." << std::endl;
			printErrors(ctl.viewer.errors, ctl.errors);
			return 1;
		}
	}
	if(!task::run(alive, &ctl)) {
		printErrors(ctl.viewer.errors, ctl.errors);
	}

	glfwTerminate();

	return 0;
}
<commit_msg>Added error printing back into main<commit_after>#include <iostream>

#include "main.hpp"
#include "util.hpp"
#include "system/printer.hpp"

#ifndef OBJ_PATH
#define OBJ_PATH "share/cube.obj"
#endif
#ifndef MTL_PATH
#define MTL_PATH "share/cube.mtl"
#endif
#ifndef VERT_PATH
#define VERT_PATH "share/fallback.vert"
#endif
#ifndef FRAG_PATH
#define FRAG_PATH "share/shade.frag"
#endif

void printErrors(std::ostream oss) {}

template<typename T1, typename... TN>
void printErrors(std::ostream oss, T1 &t1, TN &... tn) {
	for(auto e : t1) {
		oss << e << std::endl;
	}
	printErrors(oss, tn...);
}

int main(int argc, const char **argv) {
	using namespace Util;
	using namespace System;
	if(glfwInit() == 0) {
		std::cout << "Failed to initialize GLFW "
			<< glfwGetVersionString() << std::endl;
		return 1;
	}

	const char *obj_fname, *mtl_fname, *vert_fname, *frag_fname;

	if(argc >= 2) obj_fname = argv[1];
	else obj_fname = OBJ_PATH;
	if(argc >= 3) mtl_fname = argv[2];
	else mtl_fname = MTL_PATH;
	if(argc >= 4) vert_fname = argv[3];
	else vert_fname = VERT_PATH;
	if(argc >= 5) frag_fname = argv[4];
	else frag_fname = FRAG_PATH;

	std::atomic_bool alive(true);
	Control::control ctl(alive, obj_fname);
	if(!alive) {
		std::cout << "Control construction failed." << std::endl;
		printErrors(std::cout, ctl.viewer.errors, ctl.errors);
		return 1;
	}
	if(!ctl.viewer.setProg(alive, vert_fname, frag_fname)) {
		std::cout << "Failed to compile or link shaders." << std::endl;
		std::cout << "For shaders " << vert_fname << ", "
			<< frag_fname << std::endl;
		printErrors(std::cout, ctl.viewer.errors, ctl.errors);
		return 1;
	} else {
		using namespace System;
		Printer<6> printer;
		std::string cols[]{"GLFW", "OpenGL", "Path"},
			rows[]{"", "Major", "Minor", "Revision", "",
				"", "Wavefront obj", "Wavefront mtl",
				"Vertex shader", "Fragment shader", ""},
			paths[]{obj_fname, mtl_fname, vert_fname, frag_fname};
		int versions[6]{0};
		glfwGetVersion(&versions[0], &versions[2], &versions[4]);
		glGetIntegerv(GL_MAJOR_VERSION, &versions[1]);
		glGetIntegerv(GL_MINOR_VERSION, &versions[3]);
		printer.push(&rows[0], &rows[5]).level()
			.push<int, 3, 2>(versions, &cols[0], &cols[2]).level()
			.insert(0, Printer_Base::repeat(3)).level()
			.push(&rows[5], &rows[5]+6).level()
			.push<std::string, 4, 1, 31>(paths, &cols[2], &cols[3]+1).level();
		std::cout << printer << std::endl;

		if(!task::init(alive, &ctl)) {
			std::cout << "Control Initialization failed." << std::endl;
			printErrors(std::cout, ctl.viewer.errors, ctl.errors);
			return 1;
		}
	}
	if(!task::run(alive, &ctl)) {
		printErrors(std::cout, ctl.viewer.errors, ctl.errors);
	}

	glfwTerminate();

	return 0;
}
<|endoftext|>


<commit_before>//==============================================================================
// Main
//==============================================================================

#include "mainwindow.h"
#include "common.h"

//==============================================================================

#include <QDir>
#include <QPointer>
#include <QProcess>
#include <QSettings>

//==============================================================================

#include <QtSingleApplication>

//==============================================================================

using namespace OpenCOR;

//==============================================================================

void removeInstances()
{
    // Remove all 'global' instances

    QSettings(qApp->applicationName()).remove("Instances");
}

//==============================================================================

int main(int pArgc, char *pArgv[])
{
    int res;

    // Create the application

    QtSingleApplication *app = new QtSingleApplication(pArgc, pArgv);

    // Some general initialisations

    initApplication(app);

#ifndef Q_WS_WIN
    // Try to run OpenCOR as a console application
    // Note: in the case of Windows, we have two binaries (.com and .exe which
    //       are for the pure console and GUI versions of OpenCOR, resp.). This
    //       means that when a console window is open, to enter something like:
    //           C:\>OpenCOR
    //       will effectively call OpenCOR.com. From there, should there be no
    //       argument that requires console treatment, the GUI version of
    //       OpenCOR will then be launched. This is, unfortunately, the only way
    //       to have OpenCOR behave as both a console and GUI application on
    //       Windows, hence the ../winConsole/main.cpp file which is used to
    //       generate the console version of OpenCOR...

    if (consoleApplication(app, &res)) {
        // OpenCOR was run as a proper console application, so...

        delete app;

        return res;
    }
#endif

    // Send a message (containing the arguments that were passed to this
    // instance of OpenCOR) to the 'official' instance of OpenCOR, should there
    // be one. If there is no 'official' instance of OpenCOR, then just carry
    // on as normal, otherwise exit since we only want one instance of OpenCOR
    // at any given time

    QString arguments = app->arguments().join("|");

    if (app->isRunning()) {
        app->sendMessage(arguments);

        delete app;

        return 0;
    }

    // Specify where to find non-OpenCOR plugins (only required on Windows)

#ifdef Q_WS_WIN
    app->addLibraryPath( QDir(app->applicationDirPath()).canonicalPath()
                        +QDir::separator()+QString("..")
                        +QDir::separator()+"plugins");
#endif

    // Remove all 'global' instances, in case OpenCOR previously crashed or
    // something (and therefore didn't remove all of them before quitting)

    removeInstances();

    // Create the main window

    MainWindow *win = new MainWindow();

    // Keep track of the main window (required by QtSingleApplication so that it
    // can do what it's supposed to be doing)

    app->setActivationWindow(win);

    // Make sure that OpenCOR can handle the message sent by another instance of
    // itself

    QObject::connect(app, SIGNAL(messageReceived(const QString &)),
                     win, SLOT(singleAppMsgRcvd(const QString &)));

    // Show the main window

    win->show();

    // Handle the arguments

    win->handleArguments(arguments);

    // Execute the application

    res = app->exec();

    // Keep track of the application file and directory paths (in case we need
    // to restart OpenCOR)

    QString appFilePath = app->applicationFilePath();
    QString appDirPath  = app->applicationDirPath();

    // Delete the main window

    delete win;

    // Remove all 'global' instances that were created and used during this
    // session

    removeInstances();

    // Delete the application

    delete app;

    // We are done with the execution of the application, so now the question is
    // whether we need to restart or not
    // Note: we do this here rather than 'within' the GUI because once we have
    //       launched a new instance of OpenCOR, we want this instance of
    //       OpenCOR to finish as soon as possible which will be the case here
    //       since all that remains to be done is to return the result of the
    //       execution of the application...

    if (res == OpenCOR::NeedRestart)
        // Restart OpenCOR, but without providing any of the argument with which
        // OpenCOR was originally started, since we want to reset everything

        QProcess::startDetached(appFilePath, QStringList(), appDirPath);

    // We are done, so...

    return res;
}

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Working on the opening of OpenCOR-supported files from the file manager (#94).<commit_after>//==============================================================================
// Main
//==============================================================================

#include "mainwindow.h"
#include "common.h"

//==============================================================================

#include <QDir>
#include <QPointer>
#include <QProcess>
#include <QSettings>

//==============================================================================

#include <QtSingleApplication>

//==============================================================================

using namespace OpenCOR;

//==============================================================================

void removeInstances()
{
    // Remove all 'global' instances

    QSettings(qApp->applicationName()).remove("Instances");
}

//==============================================================================

int main(int pArgc, char *pArgv[])
{
    int res;

    // Create the application

    QtSingleApplication *app = new QtSingleApplication(pArgc, pArgv);

    // Some general initialisations

    initApplication(app);

#ifndef Q_WS_WIN
    // Try to run OpenCOR as a console application
    // Note: in the case of Windows, we have two binaries (.com and .exe which
    //       are for the pure console and GUI versions of OpenCOR, resp.). This
    //       means that when a console window is open, to enter something like:
    //           C:\>OpenCOR
    //       will effectively call OpenCOR.com. From there, should there be no
    //       argument that requires console treatment, the GUI version of
    //       OpenCOR will then be launched. This is, unfortunately, the only way
    //       to have OpenCOR behave as both a console and GUI application on
    //       Windows, hence the ../winConsole/main.cpp file which is used to
    //       generate the console version of OpenCOR...

    if (consoleApplication(app, &res)) {
        // OpenCOR was run as a proper console application, so...

        delete app;

        return res;
    }
#endif

    // Send a message (containing the arguments that were passed to this
    // instance of OpenCOR) to the 'official' instance of OpenCOR, should there
    // be one. If there is no 'official' instance of OpenCOR, then just carry
    // on as normal, otherwise exit since we only want one instance of OpenCOR
    // at any given time

    QString arguments = app->arguments().join("|");

    if (app->isRunning()) {
        app->sendMessage(arguments);

        delete app;

        return 0;
    }

    // Specify where to find non-OpenCOR plugins (only required on Windows)

#ifdef Q_WS_WIN
    app->addLibraryPath( QDir(app->applicationDirPath()).canonicalPath()
                        +QDir::separator()+QString("..")
                        +QDir::separator()+"plugins");
#endif

    // Remove all 'global' instances, in case OpenCOR previously crashed or
    // something (and therefore didn't remove all of them before quitting)

    removeInstances();

    // Create the main window

    MainWindow *win = new MainWindow();

    // Keep track of the main window (required by QtSingleApplication so that it
    // can do what it's supposed to be doing)

    app->setActivationWindow(win);

    // Make sure that OpenCOR can handle the message sent by another instance of
    // itself

    QObject::connect(app, SIGNAL(messageReceived(const QString &)),
                     win, SLOT(singleAppMsgRcvd(const QString &)));

    // Handle the arguments

    win->handleArguments(arguments);

    // Show the main window

    win->show();

    // Execute the application

    res = app->exec();

    // Keep track of the application file and directory paths (in case we need
    // to restart OpenCOR)

    QString appFilePath = app->applicationFilePath();
    QString appDirPath  = app->applicationDirPath();

    // Delete the main window

    delete win;

    // Remove all 'global' instances that were created and used during this
    // session

    removeInstances();

    // Delete the application

    delete app;

    // We are done with the execution of the application, so now the question is
    // whether we need to restart or not
    // Note: we do this here rather than 'within' the GUI because once we have
    //       launched a new instance of OpenCOR, we want this instance of
    //       OpenCOR to finish as soon as possible which will be the case here
    //       since all that remains to be done is to return the result of the
    //       execution of the application...

    if (res == OpenCOR::NeedRestart)
        // Restart OpenCOR, but without providing any of the argument with which
        // OpenCOR was originally started, since we want to reset everything

        QProcess::startDetached(appFilePath, QStringList(), appDirPath);

    // We are done, so...

    return res;
}

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <memory>
#include <csignal>
#include <vector>
#include <thread>

#include "RtMidi.h"
#include "portaudio.h"

#define tcm(x){ try{ x } catch(RtMidiError& e){ puts("Had an exception:"); e.printMessage(); exit(1); } };
#define tcpa(err){ if(err != paNoError){ puts(Pa_GetErrorText(err)); exit(1); } }

using namespace std;

constexpr int sample_rate = 44100;

enum MIDI_Action{
    NoteOn = 144,
    NoteOff = 128
};

inline float midi2hz(unsigned char note){
    float a = (note - 69) / 12.0f;
    return 440.0f * powf(2.0f, a);
}

inline float hz2dphase(float hz){
    return 2.0f * hz / float(sample_rate);
}

bool run = true;
static void on_sigint(int signal){
    run = false;
}

inline float lerp(float a, float b, float alpha){
    return (1.0f - alpha) * a + alpha * b;
}

float saw_wave(float phase){
    phase /= 6.2831853f;
    return lerp(-1.0f, 1.0f, phase);
}
float sine_wave(float phase){
    return sinf(phase);
}
float square_wave(float phase){
    return phase < 3.141592f ? 1.0f : -1.0f;
}
float triangle_wave(float phase){
    if(phase < 3.141592f){
        return lerp(-1.0f, 1.0f, phase / 3.141592f);
    }
    else{
        phase -= 3.141592f;
        return lerp(1.0f, -1.0f, phase / 3.141592f);
    }
}

typedef float (*wave_func)(float);

struct voices{
    float phase[8];
    float dphase[8];
    float amplitude[8];
    wave_func func;
    int tail;
    float out;
    voices() : func(&saw_wave), tail(0), out(0.0f){
        for(int i = 0; i < 8; i++){
            amplitude[i] = 0.0f;
            phase[i] = 0.0f;
            dphase[i] = 0.0f;
        }
    }
    inline void onnote(unsigned char anote){
        dphase[tail] = hz2dphase(midi2hz(anote));
        amplitude[tail] = 1.0f;
        tail = (tail+1) & 7;
    }
    inline void ontick(){
        out = 0.0f;
        for(int i = 0; i < 8; i++){
            out += amplitude[i] * func(phase[i]);
            phase[i] += dphase[i];
            phase[i] = fmod(phase[i], 6.2831853f);
            amplitude[i] *= 0.9999f;
        }
    }
};

struct midiud{
    unsigned char note;
    voices* voice;
};

static void on_message(double timestamp, vector<unsigned char>* pmessage, void* userdata){
    if(!pmessage)
        return;
    auto& message = *pmessage;
    midiud* ud = (midiud*)userdata;
    if(message.size() == 3){
        auto& action = message[0];
        auto& note = message[1];
        auto& velocity = message[2];
        if(action == NoteOn){
            ud->voice->onnote(note);
        }
        else if(action == NoteOff){
        }
    }
}

static int on_audio(const void* inbuf, void* outbuf, unsigned long num_frames,
    const PaStreamCallbackTimeInfo* timeinfo, PaStreamCallbackFlags flags, void* userdata){

    float* output = (float*)outbuf;
    voices* vcs = (voices*)userdata;
    for(unsigned i = 0; i < num_frames; i++){
        *output = vcs->out;
        output++;
        *output = vcs->out;
        output++;
        vcs->ontick();
    }

    return 0;
}

int main(){
    unique_ptr<RtMidiIn> midiin;
    tcm( midiin = make_unique<RtMidiIn>(); )

    if(midiin->getPortCount() < 1){
        puts("No ports open, quitting.");
        exit(1);
    }
    puts(midiin->getPortName(0).c_str());

    midiin->openPort(0);
    signal(SIGINT, on_sigint);
    voices phase;

    midiud midiuserdata;
    midiuserdata.note = 40;
    midiuserdata.voice = &phase;
    midiin->setCallback(on_message, &midiuserdata);

    auto err = Pa_Initialize();
    tcpa(err)

    PaStream* stream = nullptr;
    err = Pa_OpenDefaultStream(&stream, 0, 2, paFloat32, sample_rate, 32, on_audio, &phase);
    tcpa(err)

    err = Pa_StartStream(stream);
    tcpa(err)

    while(run){
        this_thread::sleep_for(0.1s);
    }

    err = Pa_StopStream(stream);
    tcpa(err)

    err = Pa_Terminate();
    tcpa(err)

    return 0;
}<commit_msg>lower amplitude to prevent clipping<commit_after>#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <memory>
#include <csignal>
#include <vector>
#include <thread>

#include "RtMidi.h"
#include "portaudio.h"

#define tcm(x){ try{ x } catch(RtMidiError& e){ puts("Had an exception:"); e.printMessage(); exit(1); } };
#define tcpa(err){ if(err != paNoError){ puts(Pa_GetErrorText(err)); exit(1); } }

using namespace std;

constexpr int sample_rate = 44100;

enum MIDI_Action{
    NoteOn = 144,
    NoteOff = 128
};

inline float midi2hz(unsigned char note){
    float a = (note - 69) / 12.0f;
    return 440.0f * powf(2.0f, a);
}

inline float hz2dphase(float hz){
    return 2.0f * hz / float(sample_rate);
}

bool run = true;
static void on_sigint(int signal){
    run = false;
}

inline float lerp(float a, float b, float alpha){
    return (1.0f - alpha) * a + alpha * b;
}

float saw_wave(float phase){
    phase /= 6.2831853f;
    return lerp(-1.0f, 1.0f, phase);
}
float sine_wave(float phase){
    return sinf(phase);
}
float square_wave(float phase){
    return phase < 3.141592f ? 1.0f : -1.0f;
}
float triangle_wave(float phase){
    if(phase < 3.141592f){
        return lerp(-1.0f, 1.0f, phase / 3.141592f);
    }
    else{
        phase -= 3.141592f;
        return lerp(1.0f, -1.0f, phase / 3.141592f);
    }
}

typedef float (*wave_func)(float);

struct voices{
    float phase[8];
    float dphase[8];
    float amplitude[8];
    wave_func func;
    int tail;
    float out;
    voices() : func(&saw_wave), tail(0), out(0.0f){
        for(int i = 0; i < 8; i++){
            amplitude[i] = 0.0f;
            phase[i] = 0.0f;
            dphase[i] = 0.0f;
        }
    }
    inline void onnote(unsigned char anote){
        dphase[tail] = hz2dphase(midi2hz(anote));
        amplitude[tail] = 0.5f;
        tail = (tail+1) & 7;
    }
    inline void ontick(){
        out = 0.0f;
        for(int i = 0; i < 8; i++){
            out += amplitude[i] * func(phase[i]);
            phase[i] += dphase[i];
            phase[i] = fmod(phase[i], 6.2831853f);
            amplitude[i] *= 0.9999f;
        }
    }
};

struct midiud{
    unsigned char note;
    voices* voice;
};

static void on_message(double timestamp, vector<unsigned char>* pmessage, void* userdata){
    if(!pmessage)
        return;
    auto& message = *pmessage;
    midiud* ud = (midiud*)userdata;
    if(message.size() == 3){
        auto& action = message[0];
        auto& note = message[1];
        auto& velocity = message[2];
        if(action == NoteOn){
            ud->voice->onnote(note);
        }
        else if(action == NoteOff){
        }
    }
}

static int on_audio(const void* inbuf, void* outbuf, unsigned long num_frames,
    const PaStreamCallbackTimeInfo* timeinfo, PaStreamCallbackFlags flags, void* userdata){

    float* output = (float*)outbuf;
    voices* vcs = (voices*)userdata;
    for(unsigned i = 0; i < num_frames; i++){
        *output = vcs->out;
        output++;
        *output = vcs->out;
        output++;
        vcs->ontick();
    }

    return 0;
}

int main(){
    unique_ptr<RtMidiIn> midiin;
    tcm( midiin = make_unique<RtMidiIn>(); )

    if(midiin->getPortCount() < 1){
        puts("No ports open, quitting.");
        exit(1);
    }
    puts(midiin->getPortName(0).c_str());

    midiin->openPort(0);
    signal(SIGINT, on_sigint);
    voices phase;

    midiud midiuserdata;
    midiuserdata.note = 40;
    midiuserdata.voice = &phase;
    midiin->setCallback(on_message, &midiuserdata);

    auto err = Pa_Initialize();
    tcpa(err)

    PaStream* stream = nullptr;
    err = Pa_OpenDefaultStream(&stream, 0, 2, paFloat32, sample_rate, 32, on_audio, &phase);
    tcpa(err)

    err = Pa_StartStream(stream);
    tcpa(err)

    while(run){
        this_thread::sleep_for(0.1s);
    }

    err = Pa_StopStream(stream);
    tcpa(err)

    err = Pa_Terminate();
    tcpa(err)

    return 0;
}<|endoftext|>