<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.

// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64

#include "net/base/file_stream.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "net/base/net_errors.h"

// We cast back and forth, so make sure it's the size we're expecting.
COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);

// Make sure our Whence mappings match the system headers.
COMPILE_ASSERT(net::FROM_BEGIN   == SEEK_SET &&
               net::FROM_CURRENT == SEEK_CUR &&
               net::FROM_END     == SEEK_END, whence_matches_system);

namespace net {
namespace {

// Map from errno to net error codes.
int64 MapErrorCode(int err) {
  switch (err) {
    case ENOENT:
      return ERR_FILE_NOT_FOUND;
    case EACCES:
      return ERR_ACCESS_DENIED;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.
int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
  // read(..., 0) returns 0 to indicate end-of-file.

  // Loop in the case of getting interrupted by a signal.
  ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
  if (res == static_cast<ssize_t>(-1))
    return MapErrorCode(errno);
  return static_cast<int>(res);
}

// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
  ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

// BackgroundReadTask is a simple task that reads a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundReadTask : public Task {
 public:
  BackgroundReadTask(base::PlatformFile file, char* buf, int buf_len,
                     CompletionCallback* callback);
  ~BackgroundReadTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundReadTask);
};

BackgroundReadTask::BackgroundReadTask(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundReadTask::~BackgroundReadTask() {}

void BackgroundReadTask::Run() {
  int result = ReadFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

// BackgroundWriteTask is a simple task that writes to a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundWriteTask : public Task {
 public:
  BackgroundWriteTask(base::PlatformFile file, const char* buf, int buf_len,
                      CompletionCallback* callback);
  ~BackgroundWriteTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  const char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundWriteTask);
};

BackgroundWriteTask::BackgroundWriteTask(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundWriteTask::~BackgroundWriteTask() {}

void BackgroundWriteTask::Run() {
  int result = WriteFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

}  // namespace

// CancelableCallbackTask takes ownership of the Callback.  This task gets
// posted to the MessageLoopForIO instance.
class CancelableCallbackTask : public CancelableTask {
 public:
  explicit CancelableCallbackTask(Callback0::Type* callback)
      : canceled_(false), callback_(callback) {}

  virtual void Run() {
    if (!canceled_)
      callback_->Run();
  }

  virtual void Cancel() {
    canceled_ = true;
  }

 private:
  bool canceled_;
  scoped_ptr<Callback0::Type> callback_;
};

// FileStream::AsyncContext ----------------------------------------------

class FileStream::AsyncContext {
 public:
  AsyncContext();
  ~AsyncContext();

  // These methods post synchronous read() and write() calls to a WorkerThread.
  void InitiateAsyncRead(
      base::PlatformFile file, char* buf, int buf_len,
      CompletionCallback* callback);
  void InitiateAsyncWrite(
      base::PlatformFile file, const char* buf, int buf_len,
      CompletionCallback* callback);

  CompletionCallback* callback() const { return callback_; }

  // Called by the WorkerPool thread executing the IO after the IO completes.
  // This method queues RunAsynchronousCallback() on the MessageLoop and signals
  // |background_io_completed_callback_|, in case the destructor is waiting.  In
  // that case, the destructor will call RunAsynchronousCallback() instead, and
  // cancel |message_loop_task_|.
  // |result| is the result of the Read/Write task.
  void OnBackgroundIOCompleted(int result);

 private:
  // Always called on the IO thread, either directly by a task on the
  // MessageLoop or by ~AsyncContext().
  void RunAsynchronousCallback();

  // The MessageLoopForIO that this AsyncContext is running on.
  MessageLoopForIO* const message_loop_;
  CompletionCallback* callback_;  // The user provided callback.

  // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool
  // thread doing the background IO on our behalf.
  CompletionCallbackImpl<AsyncContext> background_io_completed_callback_;

  // This is used to synchronize between the AsyncContext destructor (which runs
  // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
  // thread.
  base::WaitableEvent background_io_completed_;

  // These variables are only valid when background_io_completed is signaled.
  int result_;
  CancelableCallbackTask* message_loop_task_;

  bool is_closing_;

  DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};

FileStream::AsyncContext::AsyncContext()
    : message_loop_(MessageLoopForIO::current()),
      callback_(NULL),
      background_io_completed_callback_(
          this, &AsyncContext::OnBackgroundIOCompleted),
      background_io_completed_(true, false),
      message_loop_task_(NULL),
      is_closing_(false) {}

FileStream::AsyncContext::~AsyncContext() {
  is_closing_ = true;
  if (callback_) {
    // If |callback_| is non-NULL, that implies either the worker thread is
    // still running the IO task, or the completion callback is queued up on the
    // MessageLoopForIO, but AsyncContext() got deleted before then.
    const bool need_to_wait = !background_io_completed_.IsSignaled();
    base::TimeTicks start = base::TimeTicks::Now();
    RunAsynchronousCallback();
    if (need_to_wait) {
      // We want to see if we block the message loop for too long.
      UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
                          base::TimeTicks::Now() - start);
    }
  }
}

void FileStream::AsyncContext::InitiateAsyncRead(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundReadTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::InitiateAsyncWrite(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundWriteTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
  result_ = result;
  message_loop_task_ = new CancelableCallbackTask(
      NewCallback(this, &AsyncContext::RunAsynchronousCallback));
  message_loop_->PostTask(FROM_HERE, message_loop_task_);
  background_io_completed_.Signal();
}

void FileStream::AsyncContext::RunAsynchronousCallback() {
  // Wait() here ensures that all modifications from the WorkerPool thread are
  // now visible.
  background_io_completed_.Wait();

  // Either we're in the MessageLoop's task, in which case Cancel() doesn't do
  // anything, or we're in ~AsyncContext(), in which case this prevents the call
  // from happening again.  Must do it here after calling Wait().
  message_loop_task_->Cancel();
  message_loop_task_ = NULL;

  if (is_closing_) {
    callback_ = NULL;
    return;
  }

  DCHECK(callback_);
  CompletionCallback* temp = NULL;
  std::swap(temp, callback_);
  background_io_completed_.Reset();
  temp->Run(result_);
}

// FileStream ------------------------------------------------------------

FileStream::FileStream()
    : file_(base::kInvalidPlatformFileValue),
      open_flags_(0),
      auto_closed_(true) {
  DCHECK(!IsOpen());
}

FileStream::FileStream(base::PlatformFile file, int flags)
    : file_(file),
      open_flags_(flags),
      auto_closed_(false) {
  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
  // make sure we will perform asynchronous File IO to it.
  if (flags & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }
}

FileStream::~FileStream() {
  Close();
}

void FileStream::Close() {
  // Abort any existing asynchronous operations.
  async_context_.reset();

  if (file_ != base::kInvalidPlatformFileValue) {
    if (close(file_) != 0) {
      NOTREACHED();
    }
    file_ = base::kInvalidPlatformFileValue;
  }
}

int FileStream::Open(const FilePath& path, int open_flags) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  file_ = base::CreatePlatformFile(path, open_flags_, NULL);
  if (file_ == base::kInvalidPlatformFileValue) {
    LOG(WARNING) << "Failed to open file: " << errno
          << " (" << path.ToWStringHack() << ")";
    return MapErrorCode(errno);
  }

  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }

  return OK;
}

bool FileStream::IsOpen() const {
  return file_ != base::kInvalidPlatformFileValue;
}

int64 FileStream::Seek(Whence whence, int64 offset) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!async_context_.get() || !async_context_->callback());

  off_t res = lseek(file_, static_cast<off_t>(offset),
                    static_cast<int>(whence));
  if (res == static_cast<off_t>(-1))
    return MapErrorCode(errno);

  return res;
}

int64 FileStream::Available() {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = Seek(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  struct stat info;
  if (fstat(file_, &info) != 0)
    return MapErrorCode(errno);

  int64 size = static_cast<int64>(info.st_size);
  DCHECK_GT(size, cur_pos);

  return size - cur_pos;
}

int FileStream::Read(
    char* buf, int buf_len, CompletionCallback* callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncRead(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return ReadFile(file_, buf, buf_len);
  }
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = Read(buf, to_read, NULL);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(
    const char* buf, int buf_len, CompletionCallback* callback) {
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);

  if (!IsOpen())
    return ERR_UNEXPECTED;

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return WriteFile(file_, buf, buf_len);
  }
}

int64 FileStream::Truncate(int64 bytes) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We better be open for reading.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = Seek(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  int result = ftruncate(file_, bytes);
  return result == 0 ? seek_position : MapErrorCode(errno);
}

}  // namespace net
<commit_msg>Fix ~FileStream in POSIX to auto close if the flag is set. This is left from my last patch.<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.

// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64

#include "net/base/file_stream.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "net/base/net_errors.h"

// We cast back and forth, so make sure it's the size we're expecting.
COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);

// Make sure our Whence mappings match the system headers.
COMPILE_ASSERT(net::FROM_BEGIN   == SEEK_SET &&
               net::FROM_CURRENT == SEEK_CUR &&
               net::FROM_END     == SEEK_END, whence_matches_system);

namespace net {
namespace {

// Map from errno to net error codes.
int64 MapErrorCode(int err) {
  switch (err) {
    case ENOENT:
      return ERR_FILE_NOT_FOUND;
    case EACCES:
      return ERR_ACCESS_DENIED;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.
int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
  // read(..., 0) returns 0 to indicate end-of-file.

  // Loop in the case of getting interrupted by a signal.
  ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
  if (res == static_cast<ssize_t>(-1))
    return MapErrorCode(errno);
  return static_cast<int>(res);
}

// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
  ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

// BackgroundReadTask is a simple task that reads a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundReadTask : public Task {
 public:
  BackgroundReadTask(base::PlatformFile file, char* buf, int buf_len,
                     CompletionCallback* callback);
  ~BackgroundReadTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundReadTask);
};

BackgroundReadTask::BackgroundReadTask(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundReadTask::~BackgroundReadTask() {}

void BackgroundReadTask::Run() {
  int result = ReadFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

// BackgroundWriteTask is a simple task that writes to a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundWriteTask : public Task {
 public:
  BackgroundWriteTask(base::PlatformFile file, const char* buf, int buf_len,
                      CompletionCallback* callback);
  ~BackgroundWriteTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  const char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundWriteTask);
};

BackgroundWriteTask::BackgroundWriteTask(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundWriteTask::~BackgroundWriteTask() {}

void BackgroundWriteTask::Run() {
  int result = WriteFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

}  // namespace

// CancelableCallbackTask takes ownership of the Callback.  This task gets
// posted to the MessageLoopForIO instance.
class CancelableCallbackTask : public CancelableTask {
 public:
  explicit CancelableCallbackTask(Callback0::Type* callback)
      : canceled_(false), callback_(callback) {}

  virtual void Run() {
    if (!canceled_)
      callback_->Run();
  }

  virtual void Cancel() {
    canceled_ = true;
  }

 private:
  bool canceled_;
  scoped_ptr<Callback0::Type> callback_;
};

// FileStream::AsyncContext ----------------------------------------------

class FileStream::AsyncContext {
 public:
  AsyncContext();
  ~AsyncContext();

  // These methods post synchronous read() and write() calls to a WorkerThread.
  void InitiateAsyncRead(
      base::PlatformFile file, char* buf, int buf_len,
      CompletionCallback* callback);
  void InitiateAsyncWrite(
      base::PlatformFile file, const char* buf, int buf_len,
      CompletionCallback* callback);

  CompletionCallback* callback() const { return callback_; }

  // Called by the WorkerPool thread executing the IO after the IO completes.
  // This method queues RunAsynchronousCallback() on the MessageLoop and signals
  // |background_io_completed_callback_|, in case the destructor is waiting.  In
  // that case, the destructor will call RunAsynchronousCallback() instead, and
  // cancel |message_loop_task_|.
  // |result| is the result of the Read/Write task.
  void OnBackgroundIOCompleted(int result);

 private:
  // Always called on the IO thread, either directly by a task on the
  // MessageLoop or by ~AsyncContext().
  void RunAsynchronousCallback();

  // The MessageLoopForIO that this AsyncContext is running on.
  MessageLoopForIO* const message_loop_;
  CompletionCallback* callback_;  // The user provided callback.

  // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool
  // thread doing the background IO on our behalf.
  CompletionCallbackImpl<AsyncContext> background_io_completed_callback_;

  // This is used to synchronize between the AsyncContext destructor (which runs
  // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
  // thread.
  base::WaitableEvent background_io_completed_;

  // These variables are only valid when background_io_completed is signaled.
  int result_;
  CancelableCallbackTask* message_loop_task_;

  bool is_closing_;

  DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};

FileStream::AsyncContext::AsyncContext()
    : message_loop_(MessageLoopForIO::current()),
      callback_(NULL),
      background_io_completed_callback_(
          this, &AsyncContext::OnBackgroundIOCompleted),
      background_io_completed_(true, false),
      message_loop_task_(NULL),
      is_closing_(false) {}

FileStream::AsyncContext::~AsyncContext() {
  is_closing_ = true;
  if (callback_) {
    // If |callback_| is non-NULL, that implies either the worker thread is
    // still running the IO task, or the completion callback is queued up on the
    // MessageLoopForIO, but AsyncContext() got deleted before then.
    const bool need_to_wait = !background_io_completed_.IsSignaled();
    base::TimeTicks start = base::TimeTicks::Now();
    RunAsynchronousCallback();
    if (need_to_wait) {
      // We want to see if we block the message loop for too long.
      UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
                          base::TimeTicks::Now() - start);
    }
  }
}

void FileStream::AsyncContext::InitiateAsyncRead(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundReadTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::InitiateAsyncWrite(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundWriteTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
  result_ = result;
  message_loop_task_ = new CancelableCallbackTask(
      NewCallback(this, &AsyncContext::RunAsynchronousCallback));
  message_loop_->PostTask(FROM_HERE, message_loop_task_);
  background_io_completed_.Signal();
}

void FileStream::AsyncContext::RunAsynchronousCallback() {
  // Wait() here ensures that all modifications from the WorkerPool thread are
  // now visible.
  background_io_completed_.Wait();

  // Either we're in the MessageLoop's task, in which case Cancel() doesn't do
  // anything, or we're in ~AsyncContext(), in which case this prevents the call
  // from happening again.  Must do it here after calling Wait().
  message_loop_task_->Cancel();
  message_loop_task_ = NULL;

  if (is_closing_) {
    callback_ = NULL;
    return;
  }

  DCHECK(callback_);
  CompletionCallback* temp = NULL;
  std::swap(temp, callback_);
  background_io_completed_.Reset();
  temp->Run(result_);
}

// FileStream ------------------------------------------------------------

FileStream::FileStream()
    : file_(base::kInvalidPlatformFileValue),
      open_flags_(0),
      auto_closed_(true) {
  DCHECK(!IsOpen());
}

FileStream::FileStream(base::PlatformFile file, int flags)
    : file_(file),
      open_flags_(flags),
      auto_closed_(false) {
  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
  // make sure we will perform asynchronous File IO to it.
  if (flags & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }
}

FileStream::~FileStream() {
  if (auto_closed_)
    Close();
}

void FileStream::Close() {
  // Abort any existing asynchronous operations.
  async_context_.reset();

  if (file_ != base::kInvalidPlatformFileValue) {
    if (close(file_) != 0) {
      NOTREACHED();
    }
    file_ = base::kInvalidPlatformFileValue;
  }
}

int FileStream::Open(const FilePath& path, int open_flags) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  file_ = base::CreatePlatformFile(path, open_flags_, NULL);
  if (file_ == base::kInvalidPlatformFileValue) {
    LOG(WARNING) << "Failed to open file: " << errno
          << " (" << path.ToWStringHack() << ")";
    return MapErrorCode(errno);
  }

  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }

  return OK;
}

bool FileStream::IsOpen() const {
  return file_ != base::kInvalidPlatformFileValue;
}

int64 FileStream::Seek(Whence whence, int64 offset) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!async_context_.get() || !async_context_->callback());

  off_t res = lseek(file_, static_cast<off_t>(offset),
                    static_cast<int>(whence));
  if (res == static_cast<off_t>(-1))
    return MapErrorCode(errno);

  return res;
}

int64 FileStream::Available() {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = Seek(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  struct stat info;
  if (fstat(file_, &info) != 0)
    return MapErrorCode(errno);

  int64 size = static_cast<int64>(info.st_size);
  DCHECK_GT(size, cur_pos);

  return size - cur_pos;
}

int FileStream::Read(
    char* buf, int buf_len, CompletionCallback* callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncRead(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return ReadFile(file_, buf, buf_len);
  }
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = Read(buf, to_read, NULL);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(
    const char* buf, int buf_len, CompletionCallback* callback) {
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);

  if (!IsOpen())
    return ERR_UNEXPECTED;

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return WriteFile(file_, buf, buf_len);
  }
}

int64 FileStream::Truncate(int64 bytes) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We better be open for reading.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = Seek(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  int result = ftruncate(file_, bytes);
  return result == 0 ? seek_position : MapErrorCode(errno);
}

}  // namespace net
<|endoftext|>


<commit_before>#include "Debug.h"
#if (defined _WIN32 || defined _WIN64)
# include <winsock2.h>
# include <Ws2tcpip.h>

#include <BaseTsd.h>
typedef SSIZE_T ssize_t;

namespace {

	ssize_t close(SOCKET s)
	{
		return closesocket(s);
	}

	ssize_t write(SOCKET s, const char *buf, int len, int flags = 0)
	{
		return send(s, buf, len, flags);
	}

}

#pragma warning(disable: 4244 4996)
#else
# include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <cstdio>
#include <cstdlib>

#include <string>

std::string Debug::DEFAULT_HOST = "127.0.0.1";
std::string Debug::DEFAULT_PORT = "13579";
const int Debug::BUF_SIZE = 1024;

Debug::Debug()
	: sfd(-1)
{
	struct addrinfo hints;
	struct addrinfo *result, *rp;
	int s;

	/* Obtain address(es) matching host/port */

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
	hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
	hints.ai_flags = 0;
	hints.ai_protocol = 0;          /* Any protocol */
	WSADATA wsaData;
	if (WSAStartup(0x0202, &wsaData)){
   		fprintf(stderr, "winsock is not initialized!\n");
   		WSACleanup();
	}
	s = getaddrinfo(DEFAULT_HOST.c_str(), DEFAULT_PORT.c_str(), &hints, &result);
	if (s != 0)
	{
		fprintf(stderr, "Could not get address");
		return;
	}

	for (rp = result; rp != NULL; rp = rp->ai_next) {
	   sfd = socket(rp->ai_family, rp->ai_socktype,
					rp->ai_protocol);
	   if (sfd == -1)
		   continue;

	  if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
		   break;                  /* Success */

	  close(sfd);
	}

	if (rp == NULL) {               /* No address succeeded */
        fprintf(stderr, "Could not connect\n");
		sfd = -1;
		return;
    }
	freeaddrinfo(result);
}

void Debug::sendCommand(const char* str)
{
	if (sfd == -1)
		return;
	int len = strlen(str);
	int pos = 0;
	while (pos < len)
	{
		ssize_t res = write(sfd, str + pos, len);
		if (res == -1)
		{
			fprintf(stderr, "Couldn't send command");
			return;
		}
		pos += res;
	}
}

void Debug::beginPre()
{
	sendCommand("begin pre\n");
}

void Debug::endPre()
{
	sendCommand("end pre\n");
}

void Debug::beginPost()
{
	sendCommand("begin post\n");
}

void Debug::endPost()
{
	sendCommand("end post\n");
}

void Debug::beginAbs()
{
	sendCommand("begin abs\n");
}

void Debug::endAbs()
{
	sendCommand("end abs\n");
}

void Debug::writeWithColor(char* buf, int32_t color)
{
	size_t len = strlen(buf);
	float r = ((color & 0xFF0000) >> 16) / 256.0;
	float g = ((color & 0x00FF00) >> 8) / 256.0;
	float b = ((color & 0x0000FF)) / 256.0;
	sprintf(buf + len, " %f %f %f\n", r, g, b);
	sendCommand(buf);
}

void Debug::circle(double x, double y, double r, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "circle %lf %lf %lf", x, y, r);
	writeWithColor(buf, color);
}

void Debug::fillCircle(double x, double y, double r, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "fill_circle %lf %lf %lf", x, y, r);
	writeWithColor(buf, color);
}

void Debug::rect(double x1, double y1, double x2, double y2, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "rect %lf %lf %lf %lf", x1, y1, x2, y2);
	writeWithColor(buf, color);
}

void Debug::fillRect(double x1, double y1, double x2, double y2, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "fill_rect %lf %lf %lf %lf", x1, y1, x2, y2);
	writeWithColor(buf, color);
}

void Debug::arc(double x, double y, double r, double start_angle, double arc_angle, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "arc %lf %lf %lf %lf %lf", x, y, r, start_angle, arc_angle);
	writeWithColor(buf, color);
}

void Debug::fillArc(double x, double y, double r, double start_angle, double arc_angle, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "fill_arc %lf %lf %lf %lf %lf", x, y, r, start_angle, arc_angle);
	writeWithColor(buf, color);
}

void Debug::line(double x1, double y1, double x2, double y2, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "line %lf %lf %lf %lf", x1, y1, x2, y2);
	writeWithColor(buf, color);
}

void Debug::text(double x, double y, const char* text, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "text %lf %lf %s", x, y, text);
	writeWithColor(buf, color);
}
<commit_msg>Make c++ client compilable on Linux<commit_after>#include "Debug.h"
#if (defined _WIN32 || defined _WIN64)
# include <winsock2.h>
# include <Ws2tcpip.h>

#include <BaseTsd.h>
typedef SSIZE_T ssize_t;

namespace {

	ssize_t close(SOCKET s)
	{
		return closesocket(s);
	}

	ssize_t write(SOCKET s, const char *buf, int len, int flags = 0)
	{
		return send(s, buf, len, flags);
	}

}

#pragma warning(disable: 4244 4996)
#else
# include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <cstdio>
#include <cstdlib>

#include <cstring>

std::string Debug::DEFAULT_HOST = "127.0.0.1";
std::string Debug::DEFAULT_PORT = "13579";
const int Debug::BUF_SIZE = 1024;

Debug::Debug()
	: sfd(-1)
{
	struct addrinfo hints;
	struct addrinfo *result, *rp;
	int s;

	/* Obtain address(es) matching host/port */

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
	hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
	hints.ai_flags = 0;
	hints.ai_protocol = 0;          /* Any protocol */

#if (defined _WIN32 || defined _WIN64)
	WSADATA wsaData;
	if (WSAStartup(0x0202, &wsaData)){
   		fprintf(stderr, "winsock is not initialized!\n");
   		WSACleanup();
	}
#endif
	s = getaddrinfo(DEFAULT_HOST.c_str(), DEFAULT_PORT.c_str(), &hints, &result);
	if (s != 0)
	{
		fprintf(stderr, "Could not get address");
		return;
	}

	for (rp = result; rp != NULL; rp = rp->ai_next) {
	   sfd = socket(rp->ai_family, rp->ai_socktype,
					rp->ai_protocol);
	   if (sfd == -1)
		   continue;

	  if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
		   break;                  /* Success */

	  close(sfd);
	}

	if (rp == NULL) {               /* No address succeeded */
        fprintf(stderr, "Could not connect\n");
		sfd = -1;
		return;
    }
	freeaddrinfo(result);
}

void Debug::sendCommand(const char* str)
{
	if (sfd == -1)
		return;
	int len = strlen(str);
	int pos = 0;
	while (pos < len)
	{
		ssize_t res = write(sfd, str + pos, len);
		if (res == -1)
		{
			fprintf(stderr, "Couldn't send command");
			return;
		}
		pos += res;
	}
}

void Debug::beginPre()
{
	sendCommand("begin pre\n");
}

void Debug::endPre()
{
	sendCommand("end pre\n");
}

void Debug::beginPost()
{
	sendCommand("begin post\n");
}

void Debug::endPost()
{
	sendCommand("end post\n");
}

void Debug::beginAbs()
{
	sendCommand("begin abs\n");
}

void Debug::endAbs()
{
	sendCommand("end abs\n");
}

void Debug::writeWithColor(char* buf, int32_t color)
{
	size_t len = strlen(buf);
	float r = ((color & 0xFF0000) >> 16) / 256.0;
	float g = ((color & 0x00FF00) >> 8) / 256.0;
	float b = ((color & 0x0000FF)) / 256.0;
	sprintf(buf + len, " %f %f %f\n", r, g, b);
	sendCommand(buf);
}

void Debug::circle(double x, double y, double r, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "circle %lf %lf %lf", x, y, r);
	writeWithColor(buf, color);
}

void Debug::fillCircle(double x, double y, double r, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "fill_circle %lf %lf %lf", x, y, r);
	writeWithColor(buf, color);
}

void Debug::rect(double x1, double y1, double x2, double y2, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "rect %lf %lf %lf %lf", x1, y1, x2, y2);
	writeWithColor(buf, color);
}

void Debug::fillRect(double x1, double y1, double x2, double y2, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "fill_rect %lf %lf %lf %lf", x1, y1, x2, y2);
	writeWithColor(buf, color);
}

void Debug::arc(double x, double y, double r, double start_angle, double arc_angle, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "arc %lf %lf %lf %lf %lf", x, y, r, start_angle, arc_angle);
	writeWithColor(buf, color);
}

void Debug::fillArc(double x, double y, double r, double start_angle, double arc_angle, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "fill_arc %lf %lf %lf %lf %lf", x, y, r, start_angle, arc_angle);
	writeWithColor(buf, color);
}

void Debug::line(double x1, double y1, double x2, double y2, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "line %lf %lf %lf %lf", x1, y1, x2, y2);
	writeWithColor(buf, color);
}

void Debug::text(double x, double y, const char* text, int32_t color)
{
	char buf[BUF_SIZE];
	sprintf(buf, "text %lf %lf %s", x, y, text);
	writeWithColor(buf, color);
}
<|endoftext|>


<commit_before>#include "V3DFrameBuffer.h"
#include "V3DDevice.h"
#include "V3DRenderPass.h"
#include "V3DImageView.h"
#ifdef _DEBUG
#include "V3DImage.h"
#endif //_SEBUG

/***************************/
/* public - V3DFrameBuffer */
/***************************/

V3DFrameBuffer* V3DFrameBuffer::Create()
{
	return V3D_NEW_T(V3DFrameBuffer);
}

V3D_RESULT V3DFrameBuffer::Initialize(IV3DDevice* pDevice, IV3DRenderPass* pRenderPass, uint32_t attachmentCount, IV3DImageView** ppAttachments)
{
	V3D_ASSERT(attachmentCount > 0);
	V3D_ASSERT(ppAttachments != nullptr);

	m_pDevice = V3D_TO_ADD_REF(static_cast<V3DDevice*>(pDevice));
	m_pRenderPass = V3D_TO_ADD_REF(static_cast<V3DRenderPass*>(pRenderPass));

	// ----------------------------------------------------------------------------------------------------
	// t[obt@쐬
	// ----------------------------------------------------------------------------------------------------

	const V3DRenderPass::Source& renderPassSource = m_pRenderPass->GetSource();

#ifdef _DEBUG
	if (renderPassSource.debug.attachments.size() != attachmentCount)
	{
		V3D_LOG_ERROR(Log_Error_MismatchRAContainerAttachmentCount);
		return V3D_ERROR_FAIL;
	}

	bool debugSizeError = false;
	uint32_t debugErrorCount = 0;
#endif //_DEBUG

	STLVector<VkImageView> vkImageViews;
	vkImageViews.reserve(attachmentCount);

	const V3DImageView::Source& imageViewSource = static_cast<V3DImageView*>(ppAttachments[0])->GetSource();

	for (uint32_t i = 0; i < attachmentCount; i++)
	{
		V3DImageView* pImageView = static_cast<V3DImageView*>(ppAttachments[i]);
		const V3DImageView::Source& compImageViewSource = pImageView->GetSource();

#ifdef _DEBUG
		if ((imageViewSource.extent.width != compImageViewSource.extent.width) ||
			(imageViewSource.extent.height != compImageViewSource.extent.height) ||
			(imageViewSource.extent.depth != compImageViewSource.extent.depth) ||
			(imageViewSource.imageSubresourceRange.layerCount != compImageViewSource.imageSubresourceRange.layerCount))
		{
			if (debugSizeError == false)
			{
				V3D_LOG_ERROR(Log_Error_MismatchRAContainerAttachmentSize);
				debugSizeError = true;
				debugErrorCount++;
			}
		}

		const V3DImageDesc& debugImageDesc = pImageView->GetInternalImagePtr()->GetDesc();
		if ((renderPassSource.debug.attachments[i].format != debugImageDesc.format) ||
			(renderPassSource.debug.attachments[i].samples != debugImageDesc.samples))
		{
			V3D_LOG_ERROR(Log_Error_MismatchRAContainerAttachmentFormatOrSamples, i);
			debugErrorCount++;
		}
#endif //_DEBUG

		vkImageViews.push_back(compImageViewSource.imageView);

		m_ImageViews.push_back(V3D_TO_ADD_REF(pImageView));
	}

#ifdef _DEBUG
	if (debugSizeError == true)
	{
		for (uint32_t i = 0; i < attachmentCount; i++)
		{
			V3DImageView* pImageView = static_cast<V3DImageView*>(ppAttachments[i]);
			const V3DImageView::Source& imageViewSource = pImageView->GetSource();

			V3D_LOG_ERROR(L"atacchment[%u] : width[%u] height[%u] layerCount[%u]", i, imageViewSource.extent.width, imageViewSource.extent.height, imageViewSource.imageSubresourceRange.layerCount);
		}
	}

	if (debugErrorCount > 0)
	{
		return V3D_ERROR_FAIL;
	}
#endif //_DEBUG

	VkFramebufferCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
	createInfo.pNext = nullptr;
	createInfo.flags = 0;
	createInfo.renderPass = renderPassSource.renderPass;
	createInfo.attachmentCount = static_cast<uint32_t>(vkImageViews.size());
	createInfo.pAttachments = vkImageViews.data();
	createInfo.width = imageViewSource.extent.width;
	createInfo.height = imageViewSource.extent.height;
	createInfo.layers = imageViewSource.imageSubresourceRange.layerCount;

	VkResult vkResult = vkCreateFramebuffer(m_pDevice->GetSource().device, &createInfo, nullptr, &m_Source.framebuffer);
	if (vkResult != VK_SUCCESS)
	{
		return ToV3DResult(vkResult);
	}

	m_Source.extent.width = imageViewSource.extent.width;
	m_Source.extent.height = imageViewSource.extent.height;
	m_Source.layerCount = imageViewSource.imageSubresourceRange.layerCount;

	return V3D_OK;
}

const V3DFrameBuffer::Source& V3DFrameBuffer::GetSource() const
{
	return m_Source;
}

/***************************************************/
/* public override - IV3DFrameBuffer */
/***************************************************/

void V3DFrameBuffer::GetRenderPass(IV3DRenderPass** ppRenderPass)
{
	(*ppRenderPass) = V3D_TO_ADD_REF(m_pRenderPass);
}

uint32_t V3DFrameBuffer::GetAttachmentCount() const
{
	return static_cast<uint32_t>(m_ImageViews.size());
}

void V3DFrameBuffer::GetAttachment(uint32_t attachmentIndex, IV3DImageView** ppImage)
{
	(*ppImage) = V3D_TO_ADD_REF(m_ImageViews[attachmentIndex]);
}

/*************************************/
/* public override - IV3DDeviceChild */
/*************************************/

void V3DFrameBuffer::GetDevice(IV3DDevice** ppDevice)
{
	(*ppDevice) = V3D_TO_ADD_REF(m_pDevice);
}

/********************************/
/* public override - IV3DObject */
/********************************/

int64_t V3DFrameBuffer::GetRefCount() const
{
	return m_RefCounter;
}

void V3DFrameBuffer::AddRef()
{
	++m_RefCounter;
}

void V3DFrameBuffer::Release()
{
	if (--m_RefCounter == 0)
	{
		V3D_DELETE_THIS_T(this, V3DFrameBuffer);
	}
}

/****************************/
/* private - V3DFrameBuffer */
/****************************/

V3DFrameBuffer::V3DFrameBuffer() :
	m_RefCounter(1),
	m_pDevice(nullptr),
	m_pRenderPass(nullptr)
{
	m_Source.framebuffer = VK_NULL_HANDLE;
	m_Source.extent.width = 0;
	m_Source.extent.height = 0;
}

V3DFrameBuffer::~V3DFrameBuffer()
{
	if (m_Source.framebuffer != VK_NULL_HANDLE)
	{
		vkDestroyFramebuffer(m_pDevice->GetSource().device, m_Source.framebuffer, nullptr);
	}

	if (m_ImageViews.empty() == false)
	{
		STLVector<IV3DImageView*>::iterator it_begin = m_ImageViews.begin();
		STLVector<IV3DImageView*>::iterator it_end = m_ImageViews.end();
		STLVector<IV3DImageView*>::iterator it;

		for (it = it_begin; it != it_end; ++it)
		{
			V3D_RELEASE((*it));
		}
	}

	V3D_RELEASE(m_pRenderPass);
	V3D_RELEASE(m_pDevice);
}
<commit_msg>フレームバッファのイメージビューの参照を保持するベクターを初期化時に reserve するようにした<commit_after>#include "V3DFrameBuffer.h"
#include "V3DDevice.h"
#include "V3DRenderPass.h"
#include "V3DImageView.h"
#ifdef _DEBUG
#include "V3DImage.h"
#endif //_SEBUG

/***************************/
/* public - V3DFrameBuffer */
/***************************/

V3DFrameBuffer* V3DFrameBuffer::Create()
{
	return V3D_NEW_T(V3DFrameBuffer);
}

V3D_RESULT V3DFrameBuffer::Initialize(IV3DDevice* pDevice, IV3DRenderPass* pRenderPass, uint32_t attachmentCount, IV3DImageView** ppAttachments)
{
	V3D_ASSERT(attachmentCount > 0);
	V3D_ASSERT(ppAttachments != nullptr);

	m_pDevice = V3D_TO_ADD_REF(static_cast<V3DDevice*>(pDevice));
	m_pRenderPass = V3D_TO_ADD_REF(static_cast<V3DRenderPass*>(pRenderPass));

	// ----------------------------------------------------------------------------------------------------
	// t[obt@쐬
	// ----------------------------------------------------------------------------------------------------

	const V3DRenderPass::Source& renderPassSource = m_pRenderPass->GetSource();

#ifdef _DEBUG
	if (renderPassSource.debug.attachments.size() != attachmentCount)
	{
		V3D_LOG_ERROR(Log_Error_MismatchRAContainerAttachmentCount);
		return V3D_ERROR_FAIL;
	}

	bool debugSizeError = false;
	uint32_t debugErrorCount = 0;
#endif //_DEBUG

	STLVector<VkImageView> vkImageViews;
	vkImageViews.reserve(attachmentCount);

	m_ImageViews.reserve(attachmentCount);

	const V3DImageView::Source& imageViewSource = static_cast<V3DImageView*>(ppAttachments[0])->GetSource();

	for (uint32_t i = 0; i < attachmentCount; i++)
	{
		V3DImageView* pImageView = static_cast<V3DImageView*>(ppAttachments[i]);
		const V3DImageView::Source& compImageViewSource = pImageView->GetSource();

#ifdef _DEBUG
		if ((imageViewSource.extent.width != compImageViewSource.extent.width) ||
			(imageViewSource.extent.height != compImageViewSource.extent.height) ||
			(imageViewSource.extent.depth != compImageViewSource.extent.depth) ||
			(imageViewSource.imageSubresourceRange.layerCount != compImageViewSource.imageSubresourceRange.layerCount))
		{
			if (debugSizeError == false)
			{
				V3D_LOG_ERROR(Log_Error_MismatchRAContainerAttachmentSize);
				debugSizeError = true;
				debugErrorCount++;
			}
		}

		const V3DImageDesc& debugImageDesc = pImageView->GetInternalImagePtr()->GetDesc();
		if ((renderPassSource.debug.attachments[i].format != debugImageDesc.format) ||
			(renderPassSource.debug.attachments[i].samples != debugImageDesc.samples))
		{
			V3D_LOG_ERROR(Log_Error_MismatchRAContainerAttachmentFormatOrSamples, i);
			debugErrorCount++;
		}
#endif //_DEBUG

		vkImageViews.push_back(compImageViewSource.imageView);

		m_ImageViews.push_back(V3D_TO_ADD_REF(pImageView));
	}

#ifdef _DEBUG
	if (debugSizeError == true)
	{
		for (uint32_t i = 0; i < attachmentCount; i++)
		{
			V3DImageView* pImageView = static_cast<V3DImageView*>(ppAttachments[i]);
			const V3DImageView::Source& imageViewSource = pImageView->GetSource();

			V3D_LOG_ERROR(L"atacchment[%u] : width[%u] height[%u] layerCount[%u]", i, imageViewSource.extent.width, imageViewSource.extent.height, imageViewSource.imageSubresourceRange.layerCount);
		}
	}

	if (debugErrorCount > 0)
	{
		return V3D_ERROR_FAIL;
	}
#endif //_DEBUG

	VkFramebufferCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
	createInfo.pNext = nullptr;
	createInfo.flags = 0;
	createInfo.renderPass = renderPassSource.renderPass;
	createInfo.attachmentCount = static_cast<uint32_t>(vkImageViews.size());
	createInfo.pAttachments = vkImageViews.data();
	createInfo.width = imageViewSource.extent.width;
	createInfo.height = imageViewSource.extent.height;
	createInfo.layers = imageViewSource.imageSubresourceRange.layerCount;

	VkResult vkResult = vkCreateFramebuffer(m_pDevice->GetSource().device, &createInfo, nullptr, &m_Source.framebuffer);
	if (vkResult != VK_SUCCESS)
	{
		return ToV3DResult(vkResult);
	}

	m_Source.extent.width = imageViewSource.extent.width;
	m_Source.extent.height = imageViewSource.extent.height;
	m_Source.layerCount = imageViewSource.imageSubresourceRange.layerCount;

	return V3D_OK;
}

const V3DFrameBuffer::Source& V3DFrameBuffer::GetSource() const
{
	return m_Source;
}

/***************************************************/
/* public override - IV3DFrameBuffer */
/***************************************************/

void V3DFrameBuffer::GetRenderPass(IV3DRenderPass** ppRenderPass)
{
	(*ppRenderPass) = V3D_TO_ADD_REF(m_pRenderPass);
}

uint32_t V3DFrameBuffer::GetAttachmentCount() const
{
	return static_cast<uint32_t>(m_ImageViews.size());
}

void V3DFrameBuffer::GetAttachment(uint32_t attachmentIndex, IV3DImageView** ppImage)
{
	(*ppImage) = V3D_TO_ADD_REF(m_ImageViews[attachmentIndex]);
}

/*************************************/
/* public override - IV3DDeviceChild */
/*************************************/

void V3DFrameBuffer::GetDevice(IV3DDevice** ppDevice)
{
	(*ppDevice) = V3D_TO_ADD_REF(m_pDevice);
}

/********************************/
/* public override - IV3DObject */
/********************************/

int64_t V3DFrameBuffer::GetRefCount() const
{
	return m_RefCounter;
}

void V3DFrameBuffer::AddRef()
{
	++m_RefCounter;
}

void V3DFrameBuffer::Release()
{
	if (--m_RefCounter == 0)
	{
		V3D_DELETE_THIS_T(this, V3DFrameBuffer);
	}
}

/****************************/
/* private - V3DFrameBuffer */
/****************************/

V3DFrameBuffer::V3DFrameBuffer() :
	m_RefCounter(1),
	m_pDevice(nullptr),
	m_pRenderPass(nullptr)
{
	m_Source.framebuffer = VK_NULL_HANDLE;
	m_Source.extent.width = 0;
	m_Source.extent.height = 0;
}

V3DFrameBuffer::~V3DFrameBuffer()
{
	if (m_Source.framebuffer != VK_NULL_HANDLE)
	{
		vkDestroyFramebuffer(m_pDevice->GetSource().device, m_Source.framebuffer, nullptr);
	}

	if (m_ImageViews.empty() == false)
	{
		STLVector<IV3DImageView*>::iterator it_begin = m_ImageViews.begin();
		STLVector<IV3DImageView*>::iterator it_end = m_ImageViews.end();
		STLVector<IV3DImageView*>::iterator it;

		for (it = it_begin; it != it_end; ++it)
		{
			V3D_RELEASE((*it));
		}
	}

	V3D_RELEASE(m_pRenderPass);
	V3D_RELEASE(m_pDevice);
}
<|endoftext|>


<commit_before>#include "expressiongraph_wbf/controllers/position_deadzone_controller.hpp"
using namespace KDL;
namespace wbf {

	position_deadzone_controller::position_deadzone_controller(Expression<double>::Ptr _p_meas,
			Expression<double>::Ptr _lower_bound,
			Expression<double>::Ptr _upper_bound,
			Expression<double>::Ptr _K
			)
	{
		p_meas=_p_meas;
		lower_bound=_lower_bound;
		upper_bound=_upper_bound;
		K=_K;
		type="prop_dead_zone";
		size_of_output=1;
	}
	void position_deadzone_controller::update_expressions(
			const std::vector<double> & q_in,
			const std::vector<int> & q_index)
	{
		p_meas->setInputValues(q_index,q_in);
		//std::cout<<"OK"<<std::endl;
	}

	void position_deadzone_controller::update_time(double time, int time_index)
	{
		K->setInputValue(time_index,time);
		lower_bound->setInputValue(time_index,time);
		upper_bound->setInputValue(time_index,time);
	}

	 bool position_deadzone_controller::compute_action(Eigen::VectorXd &res)
	 {
		 if (res.size()!=size_of_output) return false;
		 double x=p_meas->value();
		 double l_bound=lower_bound->value();
		 double u_bound=lower_bound->value();
		 if(l_bound>u_bound) return false;
		 double k=K->value();

		 if (x<l_bound)
			 res[0]=(l_bound-x)*k;
		 else if(x>l_bound)
			 res[0]=(u_bound-x)*k;
		 else
			 res[0]=0;
		 //std::cout<<"x:\t"<<x<<"\txd:\t"<<xd<<"\tk:\t"<<k<<"\nres:\t"<<res[0]<<std::endl;
		 return true;
	 }
};
<commit_msg>add deadzone scalar controller and test of joint constraint<commit_after>#include "expressiongraph_wbf/controllers/position_deadzone_controller.hpp"
using namespace KDL;
namespace wbf {

	position_deadzone_controller::position_deadzone_controller(Expression<double>::Ptr _p_meas,
			Expression<double>::Ptr _lower_bound,
			Expression<double>::Ptr _upper_bound,
			Expression<double>::Ptr _K
			)
	{
		p_meas=_p_meas;
		lower_bound=_lower_bound;
		upper_bound=_upper_bound;
		K=_K;
		type="prop_dead_zone";
		size_of_output=1;
	}
	void position_deadzone_controller::update_expressions(
			const std::vector<double> & q_in,
			const std::vector<int> & q_index)
	{
		p_meas->setInputValues(q_index,q_in);
		//std::cout<<"OK"<<std::endl;
	}

	void position_deadzone_controller::update_time(double time, int time_index)
	{
		K->setInputValue(time_index,time);
		lower_bound->setInputValue(time_index,time);
		upper_bound->setInputValue(time_index,time);
	}

	 bool position_deadzone_controller::compute_action(Eigen::VectorXd &res)
	 {
		 if (res.size()!=size_of_output) return false;
		 double x=p_meas->value();
		 double l_bound=lower_bound->value();
		 double u_bound=upper_bound->value();
		 if(l_bound>u_bound) return false;
		 double k=K->value();

		 if (x<l_bound)
			 res[0]=(l_bound-x)*k;
		 else if(x>u_bound)
			 res[0]=(u_bound-x)*k;
		 else
			 res[0]=0;
		 //std::cout<<"x:\t"<<x<<"\txd:\t"<<xd<<"\tk:\t"<<k<<"\nres:\t"<<res[0]<<std::endl;
		 return true;
	 }
};
<|endoftext|>


<commit_before><commit_msg>Fix trim resident option in avatar nametags<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xception.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:05:54 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _XCEPTION_HXX_
#define _XCEPTION_HXX_

#ifndef _VOS_OBJECT_HXX_
#include <vos/object.hxx>
#endif

#ifdef SAL_W32
#pragma warning( disable : 4290 )
#endif

#ifdef _USE_NAMESPACE
namespace vos
{
#endif

/* avoid clashes with <vos/exception.hxx> */
#define OException OBaseException

/*
 * Macros for true try/catch based Exception Handling (public)
 * based on true rtti type checking
 */

#define THROW_AGAIN                     throw;
#define THROW( Constructor )            throw Constructor;

/*
 * declaration of the exceptions that may be thrown by a function
 * (e.g.) void myfunction(sal_Int32 a) throw ( std::bad_alloc );
 * is not fully supported by all compilers
 */

#define THROWS( ARG ) throw ARG

/*
 * just a base class for further exceptions
 */

class OException : public OObject
{
    VOS_DECLARE_CLASSINFO(VOS_NAMESPACE(OException, vos));

public:
    virtual ~OException();
    OException() {}
    OException( const OException &aPattern ) {}

    OException& SAL_CALL operator=(const OException& excp)
        { return *this; }
};

#ifdef _USE_NAMESPACE
}
#endif

#endif /* _XCEPTION_HXX_ */

<commit_msg>INTEGRATION: CWS vgcleanupmacros (1.3.18); FILE MERGED 2006/05/17 11:23:19 vg 1.3.18.1: #i65486# cleanup:remove obsolete macros<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xception.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: vg $ $Date: 2006-06-02 12:41:07 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _XCEPTION_HXX_
#define _XCEPTION_HXX_

#ifndef _VOS_OBJECT_HXX_
#include <vos/object.hxx>
#endif

#ifdef SAL_W32
#pragma warning( disable : 4290 )
#endif

namespace vos
{

/* avoid clashes with <vos/exception.hxx> */
#define OException OBaseException

/*
 * Macros for true try/catch based Exception Handling (public)
 * based on true rtti type checking
 */

#define THROW_AGAIN                     throw;
#define THROW( Constructor )            throw Constructor;

/*
 * declaration of the exceptions that may be thrown by a function
 * (e.g.) void myfunction(sal_Int32 a) throw ( std::bad_alloc );
 * is not fully supported by all compilers
 */

#define THROWS( ARG ) throw ARG

/*
 * just a base class for further exceptions
 */

class OException : public OObject
{
    VOS_DECLARE_CLASSINFO(VOS_NAMESPACE(OException, vos));

public:
    virtual ~OException();
    OException() {}
    OException( const OException &aPattern ) {}

    OException& SAL_CALL operator=(const OException& excp)
        { return *this; }
};

}

#endif /* _XCEPTION_HXX_ */

<|endoftext|>


<commit_before><commit_msg>Always remove SwModelTestBase::m_aTempFile<commit_after><|endoftext|>


<commit_before>#include "mainwindow.h"
#include <QPen>
#include <QGraphicsRectItem>
#include <QGraphicsEllipseItem>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // specify app window geometry. 1920x1080 screen rez yields a 0.56 pixel ratio
    setGeometry(56,100,600,600);

    // set up the scene
    // traditionally, member objects start with the letter 'm'
    mGraphicsScene = new QGraphicsScene(0, 0, 400, 400);

    // set up the view
    mGraphicsView = new QGraphicsView(mGraphicsScene, this);
    mGraphicsView->setGeometry(0, 0, 600, 600);
    mGraphicsView->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    mGraphicsView->setDragMode(QGraphicsView::ScrollHandDrag);

    // add a blue box that is the size of the scene
    QPen pen;
    pen.setColor(QColor(Qt::blue));
    pen.setWidth(2);
    mGraphicsScene->addRect(0, 0, mGraphicsScene->width(), mGraphicsScene->height(), pen);

    // these ints will go out of scope after constructor is called because they are not
    // defined in the mainwindow class declaration of the mainwindow.h file:
    int x = 100, y = 100, w = 10, h = 10;

    // add a black circle known as mEllipseItem to the scene
    mEllipseItem = new QGraphicsEllipseItem(x,y,w,h);
    pen.setColor(QColor(Qt::black));
    pen.setWidth(1);
    mEllipseItem->setPen(pen);
    mGraphicsScene->addItem(mEllipseItem);

    // how often we update the scene, in milliseconds:
    mUpdateIntervalMS = 60;

    // start the signal/slot timer, which invokes gameTick() every mUpdateIntervalMS milliseconds
    startGameLoopTimer();
}

MainWindow::~MainWindow()
{
    // this is the destructor code for the MainWindow object
    if (mGraphicsView != NULL)
    {
        delete mGraphicsView;
        mGraphicsView = NULL;
    }
    if (mGraphicsScene != NULL)
    {
        delete mGraphicsScene;
        mGraphicsScene = NULL;
    }
}

void MainWindow::startGameLoopTimer()
{
    // associate the signal timeout() to the slot gameTick(), and start our update timer
    QObject::connect(&mTimer, SIGNAL(timeout()), this, SLOT(gameTick()));
    mTimer.start(mUpdateIntervalMS);
}

void MainWindow::gameTick()
{
    // this code makes whatever changes to the scene you want to make, every gametick.
    // if you want to change what the animation does, you can do that here, or add new
    // functions (methods) and call them from here.

    // Change this code to make the circle stay within the blue box! :-D You could have
    // the circle just stop moving when it reaches the edge of the scene at x,y == 400,400
    // or you could make the circle change direction somehow when x or y get outside of
    // the range of 0 to 400.  Or think of some other way the circle should move!

    // you can uncomment the following line to produce console output every gametick.
    // this will generate around 16 messages per second at 60ms gametick.
    //qDebug() << "MainWindow::gameTick(): invoked\n";

    mEllipseItem->setX(mEllipseItem->x()+1);
    mEllipseItem->setY(mEllipseItem->y()+1);
    mGraphicsScene->advance();
}
<commit_msg>rearranged comments<commit_after>#include "mainwindow.h"
#include <QPen>
#include <QGraphicsRectItem>
#include <QGraphicsEllipseItem>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // specify app window geometry. 1920x1080 screen rez yields a 0.56 pixel ratio
    setGeometry(56,100,600,600);

    // set up the scene
    // traditionally, member objects start with the letter 'm'
    mGraphicsScene = new QGraphicsScene(0, 0, 400, 400);

    // set up the view
    mGraphicsView = new QGraphicsView(mGraphicsScene, this);
    mGraphicsView->setGeometry(0, 0, 600, 600);
    mGraphicsView->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    mGraphicsView->setDragMode(QGraphicsView::ScrollHandDrag);

    // add a blue box that is the size of the scene
    QPen pen;
    pen.setColor(QColor(Qt::blue));
    pen.setWidth(2);
    mGraphicsScene->addRect(0, 0, mGraphicsScene->width(), mGraphicsScene->height(), pen);

    // these ints will go out of scope after constructor is called because they are not
    // defined in the mainwindow class declaration of the mainwindow.h file:
    int x = 100, y = 100, w = 10, h = 10;

    // add a black circle known as mEllipseItem to the scene
    mEllipseItem = new QGraphicsEllipseItem(x,y,w,h);
    pen.setColor(QColor(Qt::black));
    pen.setWidth(1);
    mEllipseItem->setPen(pen);
    mGraphicsScene->addItem(mEllipseItem);

    // how often we update the scene, in milliseconds:
    mUpdateIntervalMS = 60;

    // start the signal/slot timer, which invokes gameTick() every mUpdateIntervalMS milliseconds
    startGameLoopTimer();
}

MainWindow::~MainWindow()
{
    // this is the destructor code for the MainWindow object
    if (mGraphicsView != NULL)
    {
        delete mGraphicsView;
        mGraphicsView = NULL;
    }
    if (mGraphicsScene != NULL)
    {
        delete mGraphicsScene;
        mGraphicsScene = NULL;
    }
}

void MainWindow::startGameLoopTimer()
{
    // associate the signal timeout() to the slot gameTick(), and start our update timer
    QObject::connect(&mTimer, SIGNAL(timeout()), this, SLOT(gameTick()));
    mTimer.start(mUpdateIntervalMS);
}

void MainWindow::gameTick()
{
    // this code makes whatever changes to the scene you want to make, every gametick.
    // if you want to change what the animation does, you can do that here, or add new
    // functions (methods) and call them from here.

    // Change this code to make the circle stay within the blue box! :-D You could have
    // the circle just stop moving when it reaches the edge of the scene at x,y == 400,400
    // or you could make the circle change direction somehow when x or y get outside of
    // the range of 0 to 400.  Or think of some other way the circle should move!

    // you can uncomment the following line to produce console output every gametick.
    //qDebug() << "MainWindow::gameTick(): invoked\n";
    // ...this will generate around 16 messages per second at 60ms gametick.

    mEllipseItem->setX(mEllipseItem->x()+1);
    mEllipseItem->setY(mEllipseItem->y()+1);
    mGraphicsScene->advance();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016-2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include <QString>
#include <QTcpSocket>
#include <QTimer>
#include <QFile>
#include <QUdpSocket>
#include <QVariantMap>
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"
#include "gateway_scanner.h"

/*! Inits the UPnP discorvery. */
void DeRestPluginPrivate::initUpnpDiscovery()
{
    DBG_Assert(udpSock == 0);

    initDescriptionXml();

    if (deCONZ::appArgumentNumeric("--upnp", 1) == 0)
    {
        udpSock = 0;
        udpSockOut = 0;
        joinedMulticastGroup = false;
        return;
    }

    udpSock = new QUdpSocket(this);
    udpSockOut = new QUdpSocket(this);
    joinedMulticastGroup = false;

    connect(udpSock, SIGNAL(readyRead()),
            this, SLOT(upnpReadyRead()));

    upnpTimer = new QTimer(this);
    upnpTimer->setSingleShot(false);
    connect(upnpTimer, SIGNAL(timeout()),
            this, SLOT(announceUpnp()));
    upnpTimer->start(1000); // setup phase fast interval
}

/*! Replaces description_in.xml template with dynamic content. */
void DeRestPluginPrivate::initDescriptionXml()
{
    deCONZ::ApsController *apsCtrl = deCONZ::ApsController::instance();
    QString serverRoot = apsCtrl->getParameter(deCONZ::ParamHttpRoot);

    if (!serverRoot.isEmpty())
    {
        descriptionXml.clear();
        QFile f(serverRoot + "/description_in.xml");

        if (f.open(QFile::ReadOnly))
        {
            QByteArray line;
            do {
               line = f.readLine(320);
               if (!line.isEmpty())
               {
                   line.replace(QString("{{IPADDRESS}}"), qPrintable(gwIpAddress));
                   line.replace(QString("{{PORT}}"), qPrintable(QString::number(gwPort)));
                   line.replace(QString("{{GWNAME}}"), qPrintable(gwName));
                   line.replace(QString("{{SERIAL}}"), qPrintable(gwBridgeId.left(6) + gwBridgeId.right(6)));
                   line.replace(QString("{{UUID}}"), qPrintable(gwUuid));
                   descriptionXml.append(line);

                   DBG_Printf(DBG_INFO_L2, "%s", line.constData());
               }
             } while (!line.isEmpty());
        }
    }
}

/*! Sends SSDP broadcast for announcement. */
void DeRestPluginPrivate::announceUpnp()
{
    if (udpSock->state() != QAbstractSocket::BoundState)
    {
        joinedMulticastGroup = false;
        DBG_Printf(DBG_ERROR, "UPNP socket not bound, state: %d\n", udpSock->state());
        // retry
        if (!udpSock->bind(QHostAddress("0.0.0.0"), 1900, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) // SSDP
        {
            DBG_Printf(DBG_ERROR, "UPNP error %s\n", qPrintable(udpSock->errorString()));
        }
        return;
    }

    if (!joinedMulticastGroup)
    {
        QHostAddress groupAddress("239.255.255.250");
        if (!udpSock->joinMulticastGroup(groupAddress))
        {
            DBG_Printf(DBG_ERROR, "UPNP error %s\n", qPrintable(udpSock->errorString()));
            return;
        }
        joinedMulticastGroup = true;
    }

    if (upnpTimer->interval() != (20 * 1000))
        upnpTimer->start(20 * 1000);

    QByteArray datagram = QString(QLatin1String(
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=100\r\n"
        "LOCATION: http://%1:%2/description.xml\r\n"
        "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.26.0\r\n"
        "hue-bridgeid: %3\r\n"
        "GWID.phoscon.de: %3\r\n"
        "NTS: ssdp:alive\r\n"))
            .arg(gwConfig["ipaddress"].toString())
            .arg(gwConfig["port"].toDouble())
            .arg(gwBridgeId.toUpper()).toLocal8Bit();
    QByteArray nt1 = QString(QLatin1String(
        "NT: upnp:rootdevice\r\n"
        "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
    QByteArray nt2 = QString(QLatin1String(
        "NT: uuid:%1\r\n"
        "USN: uuid:%1\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
    QByteArray nt3 = QString(QLatin1String(
        "NT: urn:schemas-upnp-org:device:basic:1\r\n"
        "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();

    quint16 port = 1900;
    QHostAddress host;
    host.setAddress(QLatin1String("239.255.255.250"));

    if (udpSockOut->writeDatagram(datagram + nt1 + "\r\n", host, port) == -1)
    {
        DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
    }
    if (udpSockOut->writeDatagram(datagram + nt2 + "\r\n", host, port) == -1)
    {
        DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
    }
    if (udpSockOut->writeDatagram(datagram + nt3 + "\r\n", host, port) == -1)
    {
        DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
    }
}

/*! Handles SSDP packets. */
void DeRestPluginPrivate::upnpReadyRead()
{
    while (udpSock->hasPendingDatagrams())
    {
        quint16 port;
        QHostAddress host;
        QByteArray datagram;
        datagram.resize(udpSock->pendingDatagramSize());
        udpSock->readDatagram(datagram.data(), datagram.size(), &host, &port);

        QTextStream stream(datagram);
        QString searchTarget;
        QString location;

        if (DBG_IsEnabled(DBG_HTTP))
        {
            DBG_Printf(DBG_HTTP, "%s\n", qPrintable(datagram));
        }

        while (!stream.atEnd())
        {
            QString line = stream.readLine();

            if (!searchTarget.isEmpty())
            {
                break;
            }

            if (line.startsWith(QLatin1String("LOCATION:")))
            {
                location = line;
            }
            else if (line.startsWith(QLatin1String("GWID.phoscon.de")))
            {
                searchTarget = line;
            }
            else if (line.startsWith(QLatin1String("hue-bridgeid")))
            {
                searchTarget = line;
            }
            else if (line.startsWith(QLatin1String("ST:")))
            {
                if (line.contains(QLatin1String("ssdp:all")) ||
                    line.contains(QLatin1String("device:basic")) ||
                    line.contains(QLatin1String("upnp:rootdevice")))
                {
                    searchTarget = line;
                }
            }
        }

        if (searchTarget.isEmpty())
        {}
        else if (datagram.startsWith("M-SEARCH *"))
        {
            QByteArray response = QString(QLatin1String(
                "HTTP/1.1 200 OK\r\n"
                "CACHE-CONTROL: max-age=100\r\n"
                "EXT:\r\n"
                "LOCATION: http://%1:%2/description.xml\r\n"
                "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.26.0\r\n"
                "hue-bridgeid: %3\r\n"
                "GWID.phoscon.de: %3\r\n"))
                    .arg(gwConfig["ipaddress"].toString())
                    .arg(gwConfig["port"].toDouble())
                    .arg(gwBridgeId.toUpper()).toLocal8Bit();
            QByteArray st1 = QString(QLatin1String(
                "ST: upnp:rootdevice\r\n"
                "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
            QByteArray st2 = QString(QLatin1String(
                "ST: uuid:%1\r\n"
                "USN: uuid:%1\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
            QByteArray st3 = QString(QLatin1String(
                "ST: urn:schemas-upnp-org:device:basic:1\r\n"
                "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();

            DBG_Printf(DBG_HTTP, "UPNP %s:%u\n%s\n", qPrintable(host.toString()), port, datagram.data());
            datagram.clear();

            if (searchTarget == "ST: ssdp:all\r\n" || searchTarget == "ST: upnp:rootdevice\r\n")
            {
                datagram.append(response);
                datagram.append(st1);
                datagram.append("\r\n");
                if (udpSockOut->writeDatagram(datagram.data(), datagram.size(), host, port) == -1)
                {
                    DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
                }
                datagram.clear();
            }
            if (searchTarget == "ST: ssdp:all\r\n" || searchTarget == QString(QLatin1String("ST: uuid:%1\r\n")).arg(gwConfig["uuid"].toString()))
            {
                datagram.append(response);
                datagram.append(st2);
                datagram.append("\r\n");
                if (udpSockOut->writeDatagram(datagram.data(), datagram.size(), host, port) == -1)
                {
                    DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
                }
                datagram.clear();
            }
            if (searchTarget == "ST ssdp:all\r\n" || searchTarget == "ST: urn:schemas-upnp-org:device:basic:1\r\n")
            {
                datagram.append(response);
                datagram.append(st3);
                datagram.append("\r\n");
                if (udpSockOut->writeDatagram(datagram.data(), datagram.size(), host, port) == -1)
                {
                    DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
                }
                datagram.clear();
            }
        }
        else if (datagram.startsWith("NOTIFY *") && !location.isEmpty())
        {
            // phoscon gateway or hue bridge
            QStringList ls = searchTarget.split(' ');
            if (ls.size() != 2)
            {
                continue;
            }

            if (ls[1] == gwBridgeId)
            {
                continue; // self
            }

            ls = location.split(' ');
            if (ls.size() != 2 || !ls[1].startsWith(QLatin1String("http://")))
            {
                continue;
            }

            // http://192.168.14.103:80/description.xml

            QUrl url(ls[1]);
            location = QString("http://%1:%2/api/config").arg(url.host()).arg(url.port(80));
            gwScanner->queryGateway(location);
        }
    }
}
<commit_msg>Fix compile typo gwIpAddress > gwIPAddress<commit_after>/*
 * Copyright (c) 2016-2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include <QString>
#include <QTcpSocket>
#include <QTimer>
#include <QFile>
#include <QUdpSocket>
#include <QVariantMap>
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"
#include "gateway_scanner.h"

/*! Inits the UPnP discorvery. */
void DeRestPluginPrivate::initUpnpDiscovery()
{
    DBG_Assert(udpSock == 0);

    initDescriptionXml();

    if (deCONZ::appArgumentNumeric("--upnp", 1) == 0)
    {
        udpSock = 0;
        udpSockOut = 0;
        joinedMulticastGroup = false;
        return;
    }

    udpSock = new QUdpSocket(this);
    udpSockOut = new QUdpSocket(this);
    joinedMulticastGroup = false;

    connect(udpSock, SIGNAL(readyRead()),
            this, SLOT(upnpReadyRead()));

    upnpTimer = new QTimer(this);
    upnpTimer->setSingleShot(false);
    connect(upnpTimer, SIGNAL(timeout()),
            this, SLOT(announceUpnp()));
    upnpTimer->start(1000); // setup phase fast interval
}

/*! Replaces description_in.xml template with dynamic content. */
void DeRestPluginPrivate::initDescriptionXml()
{
    deCONZ::ApsController *apsCtrl = deCONZ::ApsController::instance();
    QString serverRoot = apsCtrl->getParameter(deCONZ::ParamHttpRoot);

    if (!serverRoot.isEmpty())
    {
        descriptionXml.clear();
        QFile f(serverRoot + "/description_in.xml");

        if (f.open(QFile::ReadOnly))
        {
            QByteArray line;
            do {
               line = f.readLine(320);
               if (!line.isEmpty())
               {
                   line.replace(QString("{{IPADDRESS}}"), qPrintable(gwIPAddress));
                   line.replace(QString("{{PORT}}"), qPrintable(QString::number(gwPort)));
                   line.replace(QString("{{GWNAME}}"), qPrintable(gwName));
                   line.replace(QString("{{SERIAL}}"), qPrintable(gwBridgeId.left(6) + gwBridgeId.right(6)));
                   line.replace(QString("{{UUID}}"), qPrintable(gwUuid));
                   descriptionXml.append(line);

                   DBG_Printf(DBG_INFO_L2, "%s", line.constData());
               }
             } while (!line.isEmpty());
        }
    }
}

/*! Sends SSDP broadcast for announcement. */
void DeRestPluginPrivate::announceUpnp()
{
    if (udpSock->state() != QAbstractSocket::BoundState)
    {
        joinedMulticastGroup = false;
        DBG_Printf(DBG_ERROR, "UPNP socket not bound, state: %d\n", udpSock->state());
        // retry
        if (!udpSock->bind(QHostAddress("0.0.0.0"), 1900, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) // SSDP
        {
            DBG_Printf(DBG_ERROR, "UPNP error %s\n", qPrintable(udpSock->errorString()));
        }
        return;
    }

    if (!joinedMulticastGroup)
    {
        QHostAddress groupAddress("239.255.255.250");
        if (!udpSock->joinMulticastGroup(groupAddress))
        {
            DBG_Printf(DBG_ERROR, "UPNP error %s\n", qPrintable(udpSock->errorString()));
            return;
        }
        joinedMulticastGroup = true;
    }

    if (upnpTimer->interval() != (20 * 1000))
        upnpTimer->start(20 * 1000);

    QByteArray datagram = QString(QLatin1String(
        "NOTIFY * HTTP/1.1\r\n"
        "HOST: 239.255.255.250:1900\r\n"
        "CACHE-CONTROL: max-age=100\r\n"
        "LOCATION: http://%1:%2/description.xml\r\n"
        "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.26.0\r\n"
        "hue-bridgeid: %3\r\n"
        "GWID.phoscon.de: %3\r\n"
        "NTS: ssdp:alive\r\n"))
            .arg(gwConfig["ipaddress"].toString())
            .arg(gwConfig["port"].toDouble())
            .arg(gwBridgeId.toUpper()).toLocal8Bit();
    QByteArray nt1 = QString(QLatin1String(
        "NT: upnp:rootdevice\r\n"
        "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
    QByteArray nt2 = QString(QLatin1String(
        "NT: uuid:%1\r\n"
        "USN: uuid:%1\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
    QByteArray nt3 = QString(QLatin1String(
        "NT: urn:schemas-upnp-org:device:basic:1\r\n"
        "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();

    quint16 port = 1900;
    QHostAddress host;
    host.setAddress(QLatin1String("239.255.255.250"));

    if (udpSockOut->writeDatagram(datagram + nt1 + "\r\n", host, port) == -1)
    {
        DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
    }
    if (udpSockOut->writeDatagram(datagram + nt2 + "\r\n", host, port) == -1)
    {
        DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
    }
    if (udpSockOut->writeDatagram(datagram + nt3 + "\r\n", host, port) == -1)
    {
        DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
    }
}

/*! Handles SSDP packets. */
void DeRestPluginPrivate::upnpReadyRead()
{
    while (udpSock->hasPendingDatagrams())
    {
        quint16 port;
        QHostAddress host;
        QByteArray datagram;
        datagram.resize(udpSock->pendingDatagramSize());
        udpSock->readDatagram(datagram.data(), datagram.size(), &host, &port);

        QTextStream stream(datagram);
        QString searchTarget;
        QString location;

        if (DBG_IsEnabled(DBG_HTTP))
        {
            DBG_Printf(DBG_HTTP, "%s\n", qPrintable(datagram));
        }

        while (!stream.atEnd())
        {
            QString line = stream.readLine();

            if (!searchTarget.isEmpty())
            {
                break;
            }

            if (line.startsWith(QLatin1String("LOCATION:")))
            {
                location = line;
            }
            else if (line.startsWith(QLatin1String("GWID.phoscon.de")))
            {
                searchTarget = line;
            }
            else if (line.startsWith(QLatin1String("hue-bridgeid")))
            {
                searchTarget = line;
            }
            else if (line.startsWith(QLatin1String("ST:")))
            {
                if (line.contains(QLatin1String("ssdp:all")) ||
                    line.contains(QLatin1String("device:basic")) ||
                    line.contains(QLatin1String("upnp:rootdevice")))
                {
                    searchTarget = line;
                }
            }
        }

        if (searchTarget.isEmpty())
        {}
        else if (datagram.startsWith("M-SEARCH *"))
        {
            QByteArray response = QString(QLatin1String(
                "HTTP/1.1 200 OK\r\n"
                "CACHE-CONTROL: max-age=100\r\n"
                "EXT:\r\n"
                "LOCATION: http://%1:%2/description.xml\r\n"
                "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.26.0\r\n"
                "hue-bridgeid: %3\r\n"
                "GWID.phoscon.de: %3\r\n"))
                    .arg(gwConfig["ipaddress"].toString())
                    .arg(gwConfig["port"].toDouble())
                    .arg(gwBridgeId.toUpper()).toLocal8Bit();
            QByteArray st1 = QString(QLatin1String(
                "ST: upnp:rootdevice\r\n"
                "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
            QByteArray st2 = QString(QLatin1String(
                "ST: uuid:%1\r\n"
                "USN: uuid:%1\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();
            QByteArray st3 = QString(QLatin1String(
                "ST: urn:schemas-upnp-org:device:basic:1\r\n"
                "USN: uuid:%1::upnp:rootdevice\r\n")).arg(gwConfig["uuid"].toString()).toLocal8Bit();

            DBG_Printf(DBG_HTTP, "UPNP %s:%u\n%s\n", qPrintable(host.toString()), port, datagram.data());
            datagram.clear();

            if (searchTarget == "ST: ssdp:all\r\n" || searchTarget == "ST: upnp:rootdevice\r\n")
            {
                datagram.append(response);
                datagram.append(st1);
                datagram.append("\r\n");
                if (udpSockOut->writeDatagram(datagram.data(), datagram.size(), host, port) == -1)
                {
                    DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
                }
                datagram.clear();
            }
            if (searchTarget == "ST: ssdp:all\r\n" || searchTarget == QString(QLatin1String("ST: uuid:%1\r\n")).arg(gwConfig["uuid"].toString()))
            {
                datagram.append(response);
                datagram.append(st2);
                datagram.append("\r\n");
                if (udpSockOut->writeDatagram(datagram.data(), datagram.size(), host, port) == -1)
                {
                    DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
                }
                datagram.clear();
            }
            if (searchTarget == "ST ssdp:all\r\n" || searchTarget == "ST: urn:schemas-upnp-org:device:basic:1\r\n")
            {
                datagram.append(response);
                datagram.append(st3);
                datagram.append("\r\n");
                if (udpSockOut->writeDatagram(datagram.data(), datagram.size(), host, port) == -1)
                {
                    DBG_Printf(DBG_ERROR, "UDP send error %s\n", qPrintable(udpSockOut->errorString()));
                }
                datagram.clear();
            }
        }
        else if (datagram.startsWith("NOTIFY *") && !location.isEmpty())
        {
            // phoscon gateway or hue bridge
            QStringList ls = searchTarget.split(' ');
            if (ls.size() != 2)
            {
                continue;
            }

            if (ls[1] == gwBridgeId)
            {
                continue; // self
            }

            ls = location.split(' ');
            if (ls.size() != 2 || !ls[1].startsWith(QLatin1String("http://")))
            {
                continue;
            }

            // http://192.168.14.103:80/description.xml

            QUrl url(ls[1]);
            location = QString("http://%1:%2/api/config").arg(url.host()).arg(url.port(80));
            gwScanner->queryGateway(location);
        }
    }
}
<|endoftext|>