<commit_before>#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <uv.h>
#include <string>
#include <sstream>
#include <map>
#include <memory>
#include <utility>
#include <vector>

#include "../worker_platform.h"
#include "../worker_thread.h"
#include "../../message.h"
#include "../../log.h"
#include "../../lock.h"

using std::string;
using std::wstring;
using std::ostringstream;
using std::unique_ptr;
using std::shared_ptr;
using std::default_delete;
using std::map;
using std::pair;
using std::make_pair;
using std::vector;
using std::move;
using std::endl;

const DWORD DEFAULT_BUFFER_SIZE = 1024 * 1024;
const DWORD NETWORK_BUFFER_SIZE = 64 * 1024;

static void CALLBACK command_perform_helper(__in ULONG_PTR payload);

static void CALLBACK event_helper(DWORD error_code, DWORD num_bytes, LPOVERLAPPED overlapped);

static Result<string> to_utf8(const wstring &in);

static Result<wstring> to_wchar(const string &in);

template < class V = void* >
static Result<V> windows_error_result(const string &prefix);

template < class V = void* >
static Result<V> windows_error_result(const string &prefix, DWORD error_code);

class WindowsWorkerPlatform;

class Subscription {
public:
  Subscription(ChannelID channel, HANDLE root, const string &path, WindowsWorkerPlatform *platform) :
    channel{channel},
    platform{platform},
    path{path},
    root{root},
    buffer_size{DEFAULT_BUFFER_SIZE},
    buffer{new BYTE[buffer_size]},
    written{new BYTE[buffer_size]}
  {
    ZeroMemory(&overlapped, sizeof(OVERLAPPED));
    overlapped.hEvent = this;
  }

  ~Subscription()
  {
    CloseHandle(root);
  }

  Result<> schedule()
  {
    int success = ReadDirectoryChangesW(
      root, // root directory handle
      buffer.get(), // result buffer
      buffer_size, // result buffer size
      TRUE, // recursive
      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES
        | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS
        | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, // change flags
      NULL, // bytes returned
      &overlapped, // overlapped
      &event_helper // completion routine
    );
    if (!success) {
      return windows_error_result<>("Unable to subscribe to filesystem events");
    }

    return ok_result();
  }

  Result<> use_network_size()
  {
    if (buffer_size <= NETWORK_BUFFER_SIZE) {
      ostringstream out("Buffer size of ");
      out
        << buffer_size
        << " is already lower than the network buffer size "
        << NETWORK_BUFFER_SIZE;
      return error_result(out.str());
    }

    buffer_size = NETWORK_BUFFER_SIZE;
    buffer.reset(new BYTE[buffer_size]);
    written.reset(new BYTE[buffer_size]);

    return ok_result();
  }

  ChannelID get_channel() const {
    return channel;
  }

  WindowsWorkerPlatform* get_platform() const {
    return platform;
  }

  BYTE *get_written(DWORD written_size) {
    memcpy(written.get(), buffer.get(), written_size);
    return written.get();
  }

  string make_absolute(const string &sub_path)
  {
    ostringstream out;

    out << path;
    if (path.back() != '\\' && sub_path.front() != '\\') {
      out << '\\';
    }
    out << sub_path;

    return out.str();
  }

private:
  ChannelID channel;
  WindowsWorkerPlatform *platform;

  string path;
  HANDLE root;
  OVERLAPPED overlapped;

  DWORD buffer_size;
  unique_ptr<BYTE[]> buffer;
  unique_ptr<BYTE[]> written;
};

class WindowsWorkerPlatform : public WorkerPlatform {
public:
  WindowsWorkerPlatform(WorkerThread *thread) :
    WorkerPlatform(thread),
    thread_handle{0}
  {
    int err;

    err = uv_mutex_init(&thread_handle_mutex);
    if (err) {
      report_uv_error(err);
    }
  };

  ~WindowsWorkerPlatform() override
  {
    uv_mutex_destroy(&thread_handle_mutex);
  }

  Result<> wake() override
  {
    Lock lock(thread_handle_mutex);

    if (!thread_handle) {
      return ok_result();
    }

    BOOL success = QueueUserAPC(
      command_perform_helper,
      thread_handle,
      reinterpret_cast<ULONG_PTR>(this)
    );
    if (!success) {
      return windows_error_result<>("Unable to queue APC");
    }

    return ok_result();
  }

  Result<> listen() override
  {
    {
      Lock lock(thread_handle_mutex);

      HANDLE pseudo_handle = GetCurrentThread();
      BOOL success = DuplicateHandle(
        GetCurrentProcess(), // Source process
        pseudo_handle, // Source handle
        GetCurrentProcess(), // Destination process
        &thread_handle, // Destination handle
        0, // Desired access
        FALSE, // Inheritable by new processes
        DUPLICATE_SAME_ACCESS // options
      );
      if (!success) {
        Result<> r = windows_error_result<>("Unable to duplicate thread handle");
        report_error("Unable to acquire thread handle");
        return r;
      }
    }

    while (true) {
      SleepEx(INFINITE, true);
    }

    report_error("listen loop ended unexpectedly");
    return health_err_result();
  }

  Result<> handle_add_command(const ChannelID channel, const string &root_path)
  {
    LOGGER << "Watching: " << root_path << endl;

    // Convert the path to a wide-character array
    size_t wlen = MultiByteToWideChar(
      CP_UTF8, // code page
      0, // flags
      root_path.data(), // source string data
      -1, // source string length (null-terminated)
      0, // output buffer
      0 // output buffer size
    );
    if (wlen == 0) {
      return windows_error_result<>("Unable to measure UTF-16 buffer");
    }
    unique_ptr<WCHAR[]> root_path_w{new WCHAR[wlen]};
    size_t conv_success = MultiByteToWideChar(
      CP_UTF8, // code page
      0, // flags,
      root_path.data(), // source string data
      -1, // source string length (null-terminated)
      root_path_w.get(), // output buffer
      wlen // output buffer size
    );
    if (!conv_success) {
      return windows_error_result<>("Unable to convert root path to UTF-16");
    }

    // Open a directory handle
    HANDLE root = CreateFileW(
      root_path_w.get(), // file name
      FILE_LIST_DIRECTORY, // desired access
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // share mode
      NULL, // security attributes
      OPEN_EXISTING, // creation disposition
      FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // flags and attributes
      NULL // template file
    );
    if (root == INVALID_HANDLE_VALUE) {
      return windows_error_result<>("Unable to open directory handle");
    }

    // Allocate and persist the subscription
    Subscription *sub = new Subscription(channel, root, root_path, this);
    auto insert_result = subscriptions.insert(make_pair(channel, sub));
    if (!insert_result.second) {
      delete sub;

      ostringstream msg("Channel collision: ");
      msg << channel;
      return error_result(msg.str());
    }

    LOGGER << "Now watching directory " << root_path << "." << endl;

    return sub->schedule();
  }

  Result<> handle_remove_command(const ChannelID channel)
  {
    return ok_result();
  }

  Result<> handle_fs_event(DWORD error_code, DWORD num_bytes, Subscription* sub)
  {
    // Ensure that the subscription is valid.
    ChannelID channel = sub->get_channel();
    auto it = subscriptions.find(channel);
    if (it == subscriptions.end() || it->second != sub) {
      return ok_result();
    }

    // Handle errors.
    if (error_code == ERROR_OPERATION_ABORTED) {
      LOGGER << "Operation aborted." << endl;

      subscriptions.erase(it);
      delete sub;

      return ok_result();
    }

    if (error_code == ERROR_INVALID_PARAMETER) {
      Result<> resize = sub->use_network_size();
      if (resize.is_error()) return resize;

      return sub->schedule();
    }

    if (error_code == ERROR_NOTIFY_ENUM_DIR) {
      LOGGER << "Change buffer overflow. Some events may have been lost." << endl;
      return sub->schedule();
    }

    if (error_code != ERROR_SUCCESS) {
      return windows_error_result<>("Completion callback error", error_code);
    }

    // Schedule the next completion callback.
    BYTE *base = sub->get_written(num_bytes);
    Result<> next = sub->schedule();
    if (next.is_error()) {
      report_error(string(next.get_error()));
    }

    // Process received events.
    vector<Message> messages;
    bool old_path_seen = false;
    string old_path;

    while (true) {
      PFILE_NOTIFY_INFORMATION info = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(base);

      wstring wpath{info->FileName, info->FileNameLength};
      Result<string> u8r = to_utf8(wpath);
      if (u8r.is_error()) {
        LOGGER << "Skipping path: " << u8r << "." << endl;
      } else {
        string path = sub->make_absolute(u8r.get_value());

        switch (info->Action) {
        case FILE_ACTION_ADDED:
          {
            FileSystemPayload payload(channel, ACTION_CREATED, KIND_UNKNOWN, move(path), "");
            Message message(move(payload));

            LOGGER << "Emitting filesystem message " << message << "." << endl;
            messages.push_back(move(message));
          }
          break;
        case FILE_ACTION_MODIFIED:
          {
            FileSystemPayload payload(channel, ACTION_MODIFIED, KIND_UNKNOWN, move(path), "");
            Message message(move(payload));

            LOGGER << "Emitting filesystem message " << message << "." << endl;
            messages.push_back(move(message));
          }
          break;
        case FILE_ACTION_REMOVED:
          {
            FileSystemPayload payload(channel, ACTION_DELETED, KIND_UNKNOWN, move(path), "");
            Message message(move(payload));

            LOGGER << "Emitting filesystem message " << message << "." << endl;
            messages.push_back(move(message));
          }
          break;
        case FILE_ACTION_RENAMED_OLD_NAME:
          old_path_seen = true;
          old_path = move(path);
          break;
        case FILE_ACTION_RENAMED_NEW_NAME:
          if (old_path_seen) {
            // Old name received first
            {
              FileSystemPayload payload(channel, ACTION_RENAMED, KIND_UNKNOWN, move(old_path), move(path));
              Message message(move(payload));

              LOGGER << "Emitting filesystem message " << message << "." << endl;
              messages.push_back(move(message));
            }

            old_path_seen = false;
          } else {
            // No old name. Treat it as a creation
            {
              FileSystemPayload payload(channel, ACTION_CREATED, KIND_UNKNOWN, move(path), "");
              Message message(move(payload));

              LOGGER << "Emitting filesystem message " << message << "." << endl;
              messages.push_back(move(message));
            }
          }
          break;
        default:
          LOGGER << "Skipping unexpected action " << info->Action << "." << endl;
          break;
        }
      }

      if (info->NextEntryOffset == 0) {
        break;
      }
      base += info->NextEntryOffset;
    }

    if (!messages.empty()) {
      Result<> er = emit_all(messages.begin(), messages.end());
      if (er.is_error()) {
        LOGGER << "Unable to emit messages: " << er << "." << endl;
      }
    }

    return next;
  }

private:
  uv_mutex_t thread_handle_mutex;
  HANDLE thread_handle;

  map<ChannelID, Subscription*> subscriptions;
};

unique_ptr<WorkerPlatform> WorkerPlatform::for_worker(WorkerThread *thread)
{
  return unique_ptr<WorkerPlatform>(new WindowsWorkerPlatform(thread));
}

void CALLBACK command_perform_helper(__in ULONG_PTR payload)
{
  WindowsWorkerPlatform *platform = reinterpret_cast<WindowsWorkerPlatform*>(payload);
  platform->handle_commands();
}

static void CALLBACK event_helper(DWORD error_code, DWORD num_bytes, LPOVERLAPPED overlapped)
{
  Subscription *sub = static_cast<Subscription*>(overlapped->hEvent);
  Result<> r = sub->get_platform()->handle_fs_event(error_code, num_bytes, sub);
  if (r.is_error()) {
    LOGGER << "Unable to handle filesystem events: " << r << "." << endl;
  }
}

Result<string> to_utf8(const wstring &in)
{
  size_t len = WideCharToMultiByte(
    CP_UTF8, // code page
    0, // flags
    in.data(), // source string
    in.size(), // source string length
    nullptr, // destination string, null to measure
    0, // destination string length
    nullptr, // default char
    nullptr  // used default char
  );
  if (!len) {
    return windows_error_result<string>("Unable to measure string as UTF-8");
  }

  unique_ptr<char[]> payload(new char[len]);
  size_t copied = WideCharToMultiByte(
    CP_UTF8, // code page
    0, // flags
    in.data(), // source string
    in.size(), // source string length
    payload.get(), // destination string
    len, // destination string length
    nullptr, // default char
    nullptr // used default char
  );
  if (!copied) {
    return windows_error_result<string>("Unable to convert string to UTF-8");
  }

  return ok_result(string(payload.get(), len));
}

Result<wstring> to_wchar(const string &in)
{
  size_t wlen = MultiByteToWideChar(
    CP_UTF8, // code page
    0, // flags
    in.c_str(), // source string data
    -1, // source string length (null-terminated)
    0, // output buffer
    0 // output buffer size
  );
  if (wlen == 0) {
    return windows_error_result<wstring>("Unable to measure string as wide string");
  }

  unique_ptr<WCHAR[]> payload(new WCHAR[wlen]);
  size_t conv_success = MultiByteToWideChar(
    CP_UTF8, // code page
    0, // flags,
    in.c_str(), // source string data
    -1, // source string length (null-terminated)
    payload.get(), // output buffer
    wlen // output buffer size (in bytes)
  );
  if (!conv_success) {
    return windows_error_result<wstring>("Unable to convert string to wide string");
  }

  return ok_result(wstring(payload.get(), wlen - 1));
}

template < class V >
Result<V> windows_error_result(const string &prefix)
{
  return windows_error_result<V>(prefix, GetLastError());
}

template < class V >
Result<V> windows_error_result(const string &prefix, DWORD error_code)
{
  LPVOID msg_buffer;

  FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL, // source
    error_code, // message ID
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // language ID
    (LPSTR) &msg_buffer, // output buffer
    0, // size
    NULL // arguments
  );

  ostringstream msg;
  msg << prefix << "\n (" << error_code << ") " << (char*) msg_buffer;
  LocalFree(msg_buffer);

  return Result<V>::make_error(msg.str());
}
<commit_msg>Use the string => wstring conversion function<commit_after>#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <uv.h>
#include <string>
#include <sstream>
#include <map>
#include <memory>
#include <utility>
#include <vector>

#include "../worker_platform.h"
#include "../worker_thread.h"
#include "../../message.h"
#include "../../log.h"
#include "../../lock.h"

using std::string;
using std::wstring;
using std::ostringstream;
using std::unique_ptr;
using std::shared_ptr;
using std::default_delete;
using std::map;
using std::pair;
using std::make_pair;
using std::vector;
using std::move;
using std::endl;

const DWORD DEFAULT_BUFFER_SIZE = 1024 * 1024;
const DWORD NETWORK_BUFFER_SIZE = 64 * 1024;

static void CALLBACK command_perform_helper(__in ULONG_PTR payload);

static void CALLBACK event_helper(DWORD error_code, DWORD num_bytes, LPOVERLAPPED overlapped);

static Result<string> to_utf8(const wstring &in);

static Result<wstring> to_wchar(const string &in);

template < class V = void* >
static Result<V> windows_error_result(const string &prefix);

template < class V = void* >
static Result<V> windows_error_result(const string &prefix, DWORD error_code);

class WindowsWorkerPlatform;

class Subscription {
public:
  Subscription(ChannelID channel, HANDLE root, const string &path, WindowsWorkerPlatform *platform) :
    channel{channel},
    platform{platform},
    path{path},
    root{root},
    buffer_size{DEFAULT_BUFFER_SIZE},
    buffer{new BYTE[buffer_size]},
    written{new BYTE[buffer_size]}
  {
    ZeroMemory(&overlapped, sizeof(OVERLAPPED));
    overlapped.hEvent = this;
  }

  ~Subscription()
  {
    CloseHandle(root);
  }

  Result<> schedule()
  {
    int success = ReadDirectoryChangesW(
      root, // root directory handle
      buffer.get(), // result buffer
      buffer_size, // result buffer size
      TRUE, // recursive
      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES
        | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS
        | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, // change flags
      NULL, // bytes returned
      &overlapped, // overlapped
      &event_helper // completion routine
    );
    if (!success) {
      return windows_error_result<>("Unable to subscribe to filesystem events");
    }

    return ok_result();
  }

  Result<> use_network_size()
  {
    if (buffer_size <= NETWORK_BUFFER_SIZE) {
      ostringstream out("Buffer size of ");
      out
        << buffer_size
        << " is already lower than the network buffer size "
        << NETWORK_BUFFER_SIZE;
      return error_result(out.str());
    }

    buffer_size = NETWORK_BUFFER_SIZE;
    buffer.reset(new BYTE[buffer_size]);
    written.reset(new BYTE[buffer_size]);

    return ok_result();
  }

  ChannelID get_channel() const {
    return channel;
  }

  WindowsWorkerPlatform* get_platform() const {
    return platform;
  }

  BYTE *get_written(DWORD written_size) {
    memcpy(written.get(), buffer.get(), written_size);
    return written.get();
  }

  string make_absolute(const string &sub_path)
  {
    ostringstream out;

    out << path;
    if (path.back() != '\\' && sub_path.front() != '\\') {
      out << '\\';
    }
    out << sub_path;

    return out.str();
  }

private:
  ChannelID channel;
  WindowsWorkerPlatform *platform;

  string path;
  HANDLE root;
  OVERLAPPED overlapped;

  DWORD buffer_size;
  unique_ptr<BYTE[]> buffer;
  unique_ptr<BYTE[]> written;
};

class WindowsWorkerPlatform : public WorkerPlatform {
public:
  WindowsWorkerPlatform(WorkerThread *thread) :
    WorkerPlatform(thread),
    thread_handle{0}
  {
    int err;

    err = uv_mutex_init(&thread_handle_mutex);
    if (err) {
      report_uv_error(err);
    }
  };

  ~WindowsWorkerPlatform() override
  {
    uv_mutex_destroy(&thread_handle_mutex);
  }

  Result<> wake() override
  {
    Lock lock(thread_handle_mutex);

    if (!thread_handle) {
      return ok_result();
    }

    BOOL success = QueueUserAPC(
      command_perform_helper,
      thread_handle,
      reinterpret_cast<ULONG_PTR>(this)
    );
    if (!success) {
      return windows_error_result<>("Unable to queue APC");
    }

    return ok_result();
  }

  Result<> listen() override
  {
    {
      Lock lock(thread_handle_mutex);

      HANDLE pseudo_handle = GetCurrentThread();
      BOOL success = DuplicateHandle(
        GetCurrentProcess(), // Source process
        pseudo_handle, // Source handle
        GetCurrentProcess(), // Destination process
        &thread_handle, // Destination handle
        0, // Desired access
        FALSE, // Inheritable by new processes
        DUPLICATE_SAME_ACCESS // options
      );
      if (!success) {
        Result<> r = windows_error_result<>("Unable to duplicate thread handle");
        report_error("Unable to acquire thread handle");
        return r;
      }
    }

    while (true) {
      SleepEx(INFINITE, true);
    }

    report_error("listen loop ended unexpectedly");
    return health_err_result();
  }

  Result<> handle_add_command(const ChannelID channel, const string &root_path)
  {
    // Convert the path to a wide-character string
    Result<wstring> convr = to_wchar(root_path);
    if (convr.is_error()) return convr.propagate<>();
    wstring &root_path_w = convr.get_value();

    // Open a directory handle
    HANDLE root = CreateFileW(
      root_path_w.c_str(), // null-terminated wchar file name
      FILE_LIST_DIRECTORY, // desired access
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // share mode
      NULL, // security attributes
      OPEN_EXISTING, // creation disposition
      FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // flags and attributes
      NULL // template file
    );
    if (root == INVALID_HANDLE_VALUE) {
      return windows_error_result<>("Unable to open directory handle");
    }

    // Allocate and persist the subscription
    Subscription *sub = new Subscription(channel, root, root_path, this);
    auto insert_result = subscriptions.insert(make_pair(channel, sub));
    if (!insert_result.second) {
      delete sub;

      ostringstream msg("Channel collision: ");
      msg << channel;
      return error_result(msg.str());
    }

    LOGGER << "Now watching directory " << root_path << "." << endl;

    return sub->schedule();
  }

  Result<> handle_remove_command(const ChannelID channel)
  {
    return ok_result();
  }

  Result<> handle_fs_event(DWORD error_code, DWORD num_bytes, Subscription* sub)
  {
    // Ensure that the subscription is valid.
    ChannelID channel = sub->get_channel();
    auto it = subscriptions.find(channel);
    if (it == subscriptions.end() || it->second != sub) {
      return ok_result();
    }

    // Handle errors.
    if (error_code == ERROR_OPERATION_ABORTED) {
      LOGGER << "Operation aborted." << endl;

      subscriptions.erase(it);
      delete sub;

      return ok_result();
    }

    if (error_code == ERROR_INVALID_PARAMETER) {
      Result<> resize = sub->use_network_size();
      if (resize.is_error()) return resize;

      return sub->schedule();
    }

    if (error_code == ERROR_NOTIFY_ENUM_DIR) {
      LOGGER << "Change buffer overflow. Some events may have been lost." << endl;
      return sub->schedule();
    }

    if (error_code != ERROR_SUCCESS) {
      return windows_error_result<>("Completion callback error", error_code);
    }

    // Schedule the next completion callback.
    BYTE *base = sub->get_written(num_bytes);
    Result<> next = sub->schedule();
    if (next.is_error()) {
      report_error(string(next.get_error()));
    }

    // Process received events.
    vector<Message> messages;
    bool old_path_seen = false;
    string old_path;

    while (true) {
      PFILE_NOTIFY_INFORMATION info = reinterpret_cast<PFILE_NOTIFY_INFORMATION>(base);

      wstring wpath{info->FileName, info->FileNameLength};
      Result<string> u8r = to_utf8(wpath);
      if (u8r.is_error()) {
        LOGGER << "Skipping path: " << u8r << "." << endl;
      } else {
        string path = sub->make_absolute(u8r.get_value());

        switch (info->Action) {
        case FILE_ACTION_ADDED:
          {
            FileSystemPayload payload(channel, ACTION_CREATED, KIND_UNKNOWN, move(path), "");
            Message message(move(payload));

            LOGGER << "Emitting filesystem message " << message << "." << endl;
            messages.push_back(move(message));
          }
          break;
        case FILE_ACTION_MODIFIED:
          {
            FileSystemPayload payload(channel, ACTION_MODIFIED, KIND_UNKNOWN, move(path), "");
            Message message(move(payload));

            LOGGER << "Emitting filesystem message " << message << "." << endl;
            messages.push_back(move(message));
          }
          break;
        case FILE_ACTION_REMOVED:
          {
            FileSystemPayload payload(channel, ACTION_DELETED, KIND_UNKNOWN, move(path), "");
            Message message(move(payload));

            LOGGER << "Emitting filesystem message " << message << "." << endl;
            messages.push_back(move(message));
          }
          break;
        case FILE_ACTION_RENAMED_OLD_NAME:
          old_path_seen = true;
          old_path = move(path);
          break;
        case FILE_ACTION_RENAMED_NEW_NAME:
          if (old_path_seen) {
            // Old name received first
            {
              FileSystemPayload payload(channel, ACTION_RENAMED, KIND_UNKNOWN, move(old_path), move(path));
              Message message(move(payload));

              LOGGER << "Emitting filesystem message " << message << "." << endl;
              messages.push_back(move(message));
            }

            old_path_seen = false;
          } else {
            // No old name. Treat it as a creation
            {
              FileSystemPayload payload(channel, ACTION_CREATED, KIND_UNKNOWN, move(path), "");
              Message message(move(payload));

              LOGGER << "Emitting filesystem message " << message << "." << endl;
              messages.push_back(move(message));
            }
          }
          break;
        default:
          LOGGER << "Skipping unexpected action " << info->Action << "." << endl;
          break;
        }
      }

      if (info->NextEntryOffset == 0) {
        break;
      }
      base += info->NextEntryOffset;
    }

    if (!messages.empty()) {
      Result<> er = emit_all(messages.begin(), messages.end());
      if (er.is_error()) {
        LOGGER << "Unable to emit messages: " << er << "." << endl;
      }
    }

    return next;
  }

private:
  uv_mutex_t thread_handle_mutex;
  HANDLE thread_handle;

  map<ChannelID, Subscription*> subscriptions;
};

unique_ptr<WorkerPlatform> WorkerPlatform::for_worker(WorkerThread *thread)
{
  return unique_ptr<WorkerPlatform>(new WindowsWorkerPlatform(thread));
}

void CALLBACK command_perform_helper(__in ULONG_PTR payload)
{
  WindowsWorkerPlatform *platform = reinterpret_cast<WindowsWorkerPlatform*>(payload);
  platform->handle_commands();
}

static void CALLBACK event_helper(DWORD error_code, DWORD num_bytes, LPOVERLAPPED overlapped)
{
  Subscription *sub = static_cast<Subscription*>(overlapped->hEvent);
  Result<> r = sub->get_platform()->handle_fs_event(error_code, num_bytes, sub);
  if (r.is_error()) {
    LOGGER << "Unable to handle filesystem events: " << r << "." << endl;
  }
}

Result<string> to_utf8(const wstring &in)
{
  size_t len = WideCharToMultiByte(
    CP_UTF8, // code page
    0, // flags
    in.data(), // source string
    in.size(), // source string length
    nullptr, // destination string, null to measure
    0, // destination string length
    nullptr, // default char
    nullptr  // used default char
  );
  if (!len) {
    return windows_error_result<string>("Unable to measure string as UTF-8");
  }

  unique_ptr<char[]> payload(new char[len]);
  size_t copied = WideCharToMultiByte(
    CP_UTF8, // code page
    0, // flags
    in.data(), // source string
    in.size(), // source string length
    payload.get(), // destination string
    len, // destination string length
    nullptr, // default char
    nullptr // used default char
  );
  if (!copied) {
    return windows_error_result<string>("Unable to convert string to UTF-8");
  }

  return ok_result(string(payload.get(), len));
}

Result<wstring> to_wchar(const string &in)
{
  size_t wlen = MultiByteToWideChar(
    CP_UTF8, // code page
    0, // flags
    in.c_str(), // source string data
    -1, // source string length (null-terminated)
    0, // output buffer
    0 // output buffer size
  );
  if (wlen == 0) {
    return windows_error_result<wstring>("Unable to measure string as wide string");
  }

  unique_ptr<WCHAR[]> payload(new WCHAR[wlen]);
  size_t conv_success = MultiByteToWideChar(
    CP_UTF8, // code page
    0, // flags,
    in.c_str(), // source string data
    -1, // source string length (null-terminated)
    payload.get(), // output buffer
    wlen // output buffer size (in bytes)
  );
  if (!conv_success) {
    return windows_error_result<wstring>("Unable to convert string to wide string");
  }

  return ok_result(wstring(payload.get(), wlen - 1));
}

template < class V >
Result<V> windows_error_result(const string &prefix)
{
  return windows_error_result<V>(prefix, GetLastError());
}

template < class V >
Result<V> windows_error_result(const string &prefix, DWORD error_code)
{
  LPVOID msg_buffer;

  FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL, // source
    error_code, // message ID
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // language ID
    (LPSTR) &msg_buffer, // output buffer
    0, // size
    NULL // arguments
  );

  ostringstream msg;
  msg << prefix << "\n (" << error_code << ") " << (char*) msg_buffer;
  LocalFree(msg_buffer);

  return Result<V>::make_error(msg.str());
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#if !defined(CODEWARRIORDEFS_HPP)
#define CODEWARRIORDEFS_HPP

// ---------------------------------------------------------------------------
//  Include some runtime files that will be needed product wide
// ---------------------------------------------------------------------------
#include <sys/types.h>  // for size_t and ssize_t
#include <limits.h>  // for MAX of size_t and ssize_t

// ---------------------------------------------------------------------------
//  A define in the build for each project is also used to control whether
//  the export keyword is from the project's viewpoint or the client's.
//  These defines provide the platform specific keywords that they need
//  to do this.
// ---------------------------------------------------------------------------
#define PLATFORM_EXPORT
#define PLATFORM_IMPORT

// ---------------------------------------------------------------------------
//  Indicate that we do not support native bools
//  If the compiler can handle boolean itself, do not define it
// ---------------------------------------------------------------------------
// #define NO_NATIVE_BOOL

// ---------------------------------------------------------------------------
//  Each compiler might support L"" prefixed constants. There are places
//  where it is advantageous to use the L"" where it supported, to avoid
//  unnecessary transcoding.
//  If your compiler does not support it, don't define this.
// ---------------------------------------------------------------------------
// #define XML_LSTRSUPPORT

// ---------------------------------------------------------------------------
//  Define our version of the XMLCh.
// ---------------------------------------------------------------------------
typedef unsigned short  XMLCh;
typedef unsigned short  UTF16Ch;

// ---------------------------------------------------------------------------
//  Define unsigned 16 and 32 bits integers
// ---------------------------------------------------------------------------
typedef unsigned short  XMLUInt16;
typedef unsigned int    XMLUInt32;

// ---------------------------------------------------------------------------
//  Define signed 32 bits integers
// ---------------------------------------------------------------------------
typedef int             XMLInt32;

// ---------------------------------------------------------------------------
//  XMLSize_t is the unsigned integral type.
// ---------------------------------------------------------------------------
#if defined(_SIZE_T) && defined(SIZE_MAX) && defined(_SSIZE_T) && defined(SSIZE_MAX)
    typedef size_t              XMLSize_t;
    #define XML_SIZE_MAX        SIZE_MAX
    typedef ssize_t             XMLSSize_t;
    #define XML_SSIZE_MAX       SSIZE_MAX
#else
    typedef unsigned long       XMLSize_t;
    #define XML_SIZE_MAX        ULONG_MAX
    typedef long                XMLSSize_t;
    #define XML_SSIZE_MAX       LONG_MAX
#endif

// ---------------------------------------------------------------------------
//  Force on the Xerces debug token if it was on in the build environment
// ---------------------------------------------------------------------------
#ifdef _DEBUG
#define XERCES_DEBUG
#endif

// ---------------------------------------------------------------------------
//  Provide some common string ops that are different/notavail for CodeWarrior.
// ---------------------------------------------------------------------------
int stricmp(const char* const str1, const char* const  str2);
int strnicmp(const char* const str1, const char* const  str2, const unsigned int count);

// ---------------------------------------------------------------------------
//  The name of the DLL that is built by the Codewarrior version of the
//  system. We append a previously defined token which holds the DLL
//  versioning string. This is defined in XercesDefs.hpp which is what this
//  file is included into.
// ---------------------------------------------------------------------------
const char* const Xerces_DLLName = "xerces-c" Xerces_DLLVersionStr;

#endif //CODEWARRIORDEFS_HPP
<commit_msg>Tweak to build with Codewarrior 8.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#if !defined(CODEWARRIORDEFS_HPP)
#define CODEWARRIORDEFS_HPP

// ---------------------------------------------------------------------------
//  Include some runtime files that will be needed product wide
// ---------------------------------------------------------------------------
//#include <sys/types.h>  // for size_t and ssize_t
//#include <limits.h>  // for MAX of size_t and ssize_t

// ---------------------------------------------------------------------------
//  A define in the build for each project is also used to control whether
//  the export keyword is from the project's viewpoint or the client's.
//  These defines provide the platform specific keywords that they need
//  to do this.
// ---------------------------------------------------------------------------
#define PLATFORM_EXPORT
#define PLATFORM_IMPORT

// ---------------------------------------------------------------------------
//  Indicate that we do not support native bools
//  If the compiler can handle boolean itself, do not define it
// ---------------------------------------------------------------------------
// #define NO_NATIVE_BOOL

// ---------------------------------------------------------------------------
//  Each compiler might support L"" prefixed constants. There are places
//  where it is advantageous to use the L"" where it supported, to avoid
//  unnecessary transcoding.
//  If your compiler does not support it, don't define this.
// ---------------------------------------------------------------------------
// #define XML_LSTRSUPPORT

// ---------------------------------------------------------------------------
//  Define our version of the XMLCh.
// ---------------------------------------------------------------------------
typedef unsigned short  XMLCh;
typedef unsigned short  UTF16Ch;

// ---------------------------------------------------------------------------
//  Define unsigned 16 and 32 bits integers
// ---------------------------------------------------------------------------
typedef unsigned short  XMLUInt16;
typedef unsigned int    XMLUInt32;

// ---------------------------------------------------------------------------
//  Define signed 32 bits integers
// ---------------------------------------------------------------------------
typedef int             XMLInt32;

// ---------------------------------------------------------------------------
//  XMLSize_t is the unsigned integral type.
// ---------------------------------------------------------------------------
#if defined(_SIZE_T) && defined(SIZE_MAX) && defined(_SSIZE_T) && defined(SSIZE_MAX)
    typedef size_t              XMLSize_t;
    #define XML_SIZE_MAX        SIZE_MAX
    typedef ssize_t             XMLSSize_t;
    #define XML_SSIZE_MAX       SSIZE_MAX
#else
    typedef unsigned long       XMLSize_t;
    #define XML_SIZE_MAX        ULONG_MAX
    typedef long                XMLSSize_t;
    #define XML_SSIZE_MAX       LONG_MAX
#endif

// ---------------------------------------------------------------------------
//  Force on the Xerces debug token if it was on in the build environment
// ---------------------------------------------------------------------------
#ifdef _DEBUG
#define XERCES_DEBUG
#endif

// ---------------------------------------------------------------------------
//  Provide some common string ops that are different/notavail for CodeWarrior.
// ---------------------------------------------------------------------------
int stricmp(const char* const str1, const char* const  str2);
int strnicmp(const char* const str1, const char* const  str2, const unsigned int count);

// ---------------------------------------------------------------------------
//  The name of the DLL that is built by the Codewarrior version of the
//  system. We append a previously defined token which holds the DLL
//  versioning string. This is defined in XercesDefs.hpp which is what this
//  file is included into.
// ---------------------------------------------------------------------------
const char* const Xerces_DLLName = "xerces-c" Xerces_DLLVersionStr;

#endif //CODEWARRIORDEFS_HPP
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <sal/config.h>
#include <vcl/opengl/OpenGLHelper.hxx>

#include "vcl/salbtype.hxx"

#include "opengl/texture.hxx"

// texture with allocated size
ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
    mnRefCount( 1 ),
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFilter( GL_NEAREST )
{
    glGenTextures( 1, &mnTexture );
    glBindTexture( GL_TEXTURE_2D, mnTexture );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    if( bAllocate )
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
    glBindTexture( GL_TEXTURE_2D, 0 );

    SAL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " allocate" );

    CHECK_GL_ERROR();
}

// texture with content retrieved from FBO
ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
    mnRefCount( 1 ),
    mnTexture( 0 ),
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFilter( GL_NEAREST )
{
    // FIXME We need the window height here
    // nY = GetHeight() - nHeight - nY;

    glGenTextures( 1, &mnTexture );
    glBindTexture( GL_TEXTURE_2D, mnTexture );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 );
    CHECK_GL_ERROR();
    glBindTexture( GL_TEXTURE_2D, 0 );

    SAL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from x" << nX << ", y" << nY );

    CHECK_GL_ERROR();
}

// texture from buffer data
ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) :
    mnRefCount( 1 ),
    mnTexture( 0 ),
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFilter( GL_NEAREST )
{
    if( !mnTexture )
        glGenTextures( 1, &mnTexture );
    glBindTexture( GL_TEXTURE_2D, mnTexture );
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mnWidth, mnHeight, 0, nFormat, nType, pData );
    glBindTexture( GL_TEXTURE_2D, 0 );

    SAL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" );

    CHECK_GL_ERROR();
}

ImplOpenGLTexture::~ImplOpenGLTexture()
{
    SAL_INFO( "vcl.opengl", "~OpenGLTexture " << mnTexture );
    if( mnTexture != 0 )
        glDeleteTextures( 1, &mnTexture );
}

OpenGLTexture::OpenGLTexture() :
    maRect( 0, 0, 0, 0 ),
    mpImpl( NULL )
{
}

OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
    maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
{
    mpImpl = new ImplOpenGLTexture( nWidth, nHeight, bAllocate );
}

OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
    maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
{
    mpImpl = new ImplOpenGLTexture( nX, nY, nWidth, nHeight );
}

OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) :
    maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
{
    mpImpl = new ImplOpenGLTexture( nWidth, nHeight, nFormat, nType, pData );
}

OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture )
{
    maRect = rTexture.maRect;
    mpImpl = rTexture.mpImpl;
    if( mpImpl )
        mpImpl->mnRefCount++;
}

OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture,
                              int nX, int nY, int nWidth, int nHeight )
{
    maRect = Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ),
                        Size( nWidth, nHeight ) );
    mpImpl = rTexture.mpImpl;
    if( mpImpl )
        mpImpl->mnRefCount++;
    SAL_INFO( "vcl.opengl", "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
}

OpenGLTexture::~OpenGLTexture()
{
    if( mpImpl )
    {
        if( mpImpl->mnRefCount == 1 )
            delete mpImpl;
        else
            mpImpl->mnRefCount--;
    }
}

bool OpenGLTexture::IsUnique() const
{
    return ( mpImpl == NULL || mpImpl->mnRefCount == 1 );
}

GLuint OpenGLTexture::Id() const
{
    if( mpImpl )
        return mpImpl->mnTexture;
    return 0;
}

int OpenGLTexture::GetWidth() const
{
    return maRect.GetWidth();
}

int OpenGLTexture::GetHeight() const
{
    return maRect.GetHeight();
}

void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const
{
    SAL_INFO( "vcl.opengl", "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
    pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth;
    pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth;

    if( !bInverted )
    {
        pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
        pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
    }
    else
    {
        pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
        pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
    }
}

void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
{
    if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
    {
        pCoord[0] = pCoord[2] = maRect.Left() / (double) mpImpl->mnWidth;
        pCoord[4] = pCoord[6] = maRect.Right() / (double) mpImpl->mnWidth;
        pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / (double) mpImpl->mnHeight;
        pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / (double) mpImpl->mnHeight;
    }
    else
    {
        pCoord[0] = pCoord[2] = 0;
        pCoord[4] = pCoord[6] = 1;
        pCoord[1] = pCoord[7] = 0;
        pCoord[3] = pCoord[5] = 1;
    }
}

GLenum OpenGLTexture::GetFilter() const
{
    if( mpImpl )
        return mpImpl->mnFilter;
    return GL_NEAREST;
}

void OpenGLTexture::SetFilter( GLenum nFilter )
{
    if( mpImpl )
    {
        mpImpl->mnFilter = nFilter;
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter );
    }

    CHECK_GL_ERROR();
}

void OpenGLTexture::Bind()
{
    if( mpImpl )
        glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );

    CHECK_GL_ERROR();
}

void OpenGLTexture::Unbind()
{
    if( mpImpl )
        glBindTexture( GL_TEXTURE_2D, 0 );

    CHECK_GL_ERROR();
}

bool OpenGLTexture::Draw()
{
    GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
    GLfloat aTexCoord[8];

    if( mpImpl == NULL )
    {
        SAL_WARN( "vcl.opengl", "Can't draw invalid texture" );
        return false;
    }

    SAL_INFO( "vcl.opengl", "Drawing texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );

    GetWholeCoord( aTexCoord );
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, aPosition );
    glEnableVertexAttribArray( 1 );
    glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
    glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
    glDisableVertexAttribArray( 0 );
    glDisableVertexAttribArray( 1 );
    glBindTexture( GL_TEXTURE_2D, 0 );

    CHECK_GL_ERROR();
    return true;
}

void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData )
{
    if( mpImpl == NULL )
    {
        SAL_WARN( "vcl.opengl", "Can't read invalid texture" );
        return;
    }

    Bind();
    glPixelStorei( GL_PACK_ALIGNMENT, 1 );

    SAL_INFO( "vcl.opengl", "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() );

    if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight )
    {
        // XXX: Call not available with GLES 2.0
        glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData );
    }
    else
    {
        GLuint nFramebufferId;
        glGenFramebuffers( 1, &nFramebufferId );
        glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId );
        CHECK_GL_ERROR();

        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Id(), 0 );
        CHECK_GL_ERROR();
        glReadPixels( maRect.Left(), mpImpl->mnHeight - maRect.Top(), GetWidth(), GetHeight(), nFormat, nType, pData );
        CHECK_GL_ERROR();

        glBindFramebuffer( GL_FRAMEBUFFER, 0 );
        glDeleteFramebuffers( 1, &nFramebufferId );

        int bpp = (nFormat == GL_RGB) ? 3 : 4;
        memset( pData, 255, GetWidth() * GetHeight() * bpp );
    }

    Unbind();
    CHECK_GL_ERROR();
}

OpenGLTexture::operator bool() const
{
    return ( mpImpl != NULL );
}

OpenGLTexture&  OpenGLTexture::operator=( const OpenGLTexture& rTexture )
{
    if( rTexture.mpImpl )
        rTexture.mpImpl->mnRefCount++;
    if( mpImpl )
    {
        if( mpImpl->mnRefCount == 1 )
            delete mpImpl;
        else
            mpImpl->mnRefCount--;
    }

    maRect = rTexture.maRect;
    mpImpl = rTexture.mpImpl;

    return *this;
}

bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const
{
    return (mpImpl == rTexture.mpImpl && maRect == rTexture.maRect );
}

bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const
{
    return !( *this == rTexture );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>vcl: Acquire framebuffer from current context when reading back texture<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <sal/config.h>
#include <vcl/opengl/OpenGLContext.hxx>
#include <vcl/opengl/OpenGLHelper.hxx>

#include "svdata.hxx"

#include "vcl/salbtype.hxx"

#include "opengl/framebuffer.hxx"
#include "opengl/texture.hxx"

// texture with allocated size
ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
    mnRefCount( 1 ),
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFilter( GL_NEAREST )
{
    glGenTextures( 1, &mnTexture );
    glBindTexture( GL_TEXTURE_2D, mnTexture );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    if( bAllocate )
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
    glBindTexture( GL_TEXTURE_2D, 0 );

    SAL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " allocate" );

    CHECK_GL_ERROR();
}

// texture with content retrieved from FBO
ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
    mnRefCount( 1 ),
    mnTexture( 0 ),
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFilter( GL_NEAREST )
{
    // FIXME We need the window height here
    // nY = GetHeight() - nHeight - nY;

    glGenTextures( 1, &mnTexture );
    glBindTexture( GL_TEXTURE_2D, mnTexture );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 );
    CHECK_GL_ERROR();
    glBindTexture( GL_TEXTURE_2D, 0 );

    SAL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from x" << nX << ", y" << nY );

    CHECK_GL_ERROR();
}

// texture from buffer data
ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) :
    mnRefCount( 1 ),
    mnTexture( 0 ),
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFilter( GL_NEAREST )
{
    if( !mnTexture )
        glGenTextures( 1, &mnTexture );
    glBindTexture( GL_TEXTURE_2D, mnTexture );
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mnWidth, mnHeight, 0, nFormat, nType, pData );
    glBindTexture( GL_TEXTURE_2D, 0 );

    SAL_INFO( "vcl.opengl", "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" );

    CHECK_GL_ERROR();
}

ImplOpenGLTexture::~ImplOpenGLTexture()
{
    SAL_INFO( "vcl.opengl", "~OpenGLTexture " << mnTexture );
    if( mnTexture != 0 )
        glDeleteTextures( 1, &mnTexture );
}

OpenGLTexture::OpenGLTexture() :
    maRect( 0, 0, 0, 0 ),
    mpImpl( NULL )
{
}

OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
    maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
{
    mpImpl = new ImplOpenGLTexture( nWidth, nHeight, bAllocate );
}

OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
    maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
{
    mpImpl = new ImplOpenGLTexture( nX, nY, nWidth, nHeight );
}

OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) :
    maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
{
    mpImpl = new ImplOpenGLTexture( nWidth, nHeight, nFormat, nType, pData );
}

OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture )
{
    maRect = rTexture.maRect;
    mpImpl = rTexture.mpImpl;
    if( mpImpl )
        mpImpl->mnRefCount++;
}

OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture,
                              int nX, int nY, int nWidth, int nHeight )
{
    maRect = Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ),
                        Size( nWidth, nHeight ) );
    mpImpl = rTexture.mpImpl;
    if( mpImpl )
        mpImpl->mnRefCount++;
    SAL_INFO( "vcl.opengl", "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
}

OpenGLTexture::~OpenGLTexture()
{
    if( mpImpl )
    {
        if( mpImpl->mnRefCount == 1 )
            delete mpImpl;
        else
            mpImpl->mnRefCount--;
    }
}

bool OpenGLTexture::IsUnique() const
{
    return ( mpImpl == NULL || mpImpl->mnRefCount == 1 );
}

GLuint OpenGLTexture::Id() const
{
    if( mpImpl )
        return mpImpl->mnTexture;
    return 0;
}

int OpenGLTexture::GetWidth() const
{
    return maRect.GetWidth();
}

int OpenGLTexture::GetHeight() const
{
    return maRect.GetHeight();
}

void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const
{
    SAL_INFO( "vcl.opengl", "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
    pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth;
    pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth;

    if( !bInverted )
    {
        pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
        pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
    }
    else
    {
        pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
        pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
    }
}

void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
{
    if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
    {
        pCoord[0] = pCoord[2] = maRect.Left() / (double) mpImpl->mnWidth;
        pCoord[4] = pCoord[6] = maRect.Right() / (double) mpImpl->mnWidth;
        pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / (double) mpImpl->mnHeight;
        pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / (double) mpImpl->mnHeight;
    }
    else
    {
        pCoord[0] = pCoord[2] = 0;
        pCoord[4] = pCoord[6] = 1;
        pCoord[1] = pCoord[7] = 0;
        pCoord[3] = pCoord[5] = 1;
    }
}

GLenum OpenGLTexture::GetFilter() const
{
    if( mpImpl )
        return mpImpl->mnFilter;
    return GL_NEAREST;
}

void OpenGLTexture::SetFilter( GLenum nFilter )
{
    if( mpImpl )
    {
        mpImpl->mnFilter = nFilter;
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter );
    }

    CHECK_GL_ERROR();
}

void OpenGLTexture::Bind()
{
    if( mpImpl )
        glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );

    CHECK_GL_ERROR();
}

void OpenGLTexture::Unbind()
{
    if( mpImpl )
        glBindTexture( GL_TEXTURE_2D, 0 );

    CHECK_GL_ERROR();
}

bool OpenGLTexture::Draw()
{
    GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 };
    GLfloat aTexCoord[8];

    if( mpImpl == NULL )
    {
        SAL_WARN( "vcl.opengl", "Can't draw invalid texture" );
        return false;
    }

    SAL_INFO( "vcl.opengl", "Drawing texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );

    GetWholeCoord( aTexCoord );
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, aPosition );
    glEnableVertexAttribArray( 1 );
    glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord );
    glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
    glDisableVertexAttribArray( 0 );
    glDisableVertexAttribArray( 1 );
    glBindTexture( GL_TEXTURE_2D, 0 );

    CHECK_GL_ERROR();
    return true;
}

void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData )
{
    if( mpImpl == NULL )
    {
        SAL_WARN( "vcl.opengl", "Can't read invalid texture" );
        return;
    }

    Bind();
    glPixelStorei( GL_PACK_ALIGNMENT, 1 );

    SAL_INFO( "vcl.opengl", "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() );

    if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight )
    {
        // XXX: Call not available with GLES 2.0
        glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData );
    }
    else
    {
        // Retrieve current context
        ImplSVData* pSVData = ImplGetSVData();
        OpenGLContext* pContext = pSVData->maGDIData.mpLastContext;
        OpenGLFramebuffer* pFramebuffer;

        pFramebuffer = pContext->AcquireFramebuffer( *this );
        glReadPixels( maRect.Left(), mpImpl->mnHeight - maRect.Top(), GetWidth(), GetHeight(), nFormat, nType, pData );
        pContext->ReleaseFramebuffer( pFramebuffer );
        CHECK_GL_ERROR();
    }

    Unbind();
    CHECK_GL_ERROR();
}

OpenGLTexture::operator bool() const
{
    return ( mpImpl != NULL );
}

OpenGLTexture&  OpenGLTexture::operator=( const OpenGLTexture& rTexture )
{
    if( rTexture.mpImpl )
        rTexture.mpImpl->mnRefCount++;
    if( mpImpl )
    {
        if( mpImpl->mnRefCount == 1 )
            delete mpImpl;
        else
            mpImpl->mnRefCount--;
    }

    maRect = rTexture.maRect;
    mpImpl = rTexture.mpImpl;

    return *this;
}

bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const
{
    return (mpImpl == rTexture.mpImpl && maRect == rTexture.maRect );
}

bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const
{
    return !( *this == rTexture );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRepFill.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Face.hxx>
# include <TopoDS_Shell.hxx>
#endif

#include "PartFeatures.h"

using namespace Part;

PROPERTY_SOURCE(Part::RuledSurface, Part::Feature)

RuledSurface::RuledSurface()
{
    ADD_PROPERTY_TYPE(Curve1,(0),"Ruled Surface",App::Prop_None,"Curve of ruled surface");
    ADD_PROPERTY_TYPE(Curve2,(0),"Ruled Surface",App::Prop_None,"Curve of ruled surface");
}

short RuledSurface::mustExecute() const
{
    if (Curve1.isTouched())
        return 1;
    if (Curve2.isTouched())
        return 1;
    return 0;
}

void RuledSurface::onChanged(const App::Property* prop)
{
    Part::Feature::onChanged(prop);
}

App::DocumentObjectExecReturn *RuledSurface::execute(void)
{
    try {
        App::DocumentObject* c1 = Curve1.getValue();
        if (!(c1 && c1->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
            return new App::DocumentObjectExecReturn("No shape linked.");
        const std::vector<std::string>& element1 = Curve1.getSubValues();
        if (element1.size() != 1)
            return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
        App::DocumentObject* c2 = Curve2.getValue();
        if (!(c2 && c2->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
            return new App::DocumentObjectExecReturn("No shape linked.");
        const std::vector<std::string>& element2 = Curve2.getSubValues();
        if (element2.size() != 1)
            return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");

        TopoDS_Shape curve1;
        const Part::TopoShape& shape1 = static_cast<Part::Feature*>(c1)->Shape.getValue();
        if (!shape1._Shape.IsNull()) {
            if (shape1._Shape.ShapeType() == TopAbs_EDGE)
                curve1 = shape1._Shape;
            else
                curve1 = shape1.getSubShape(element1[0].c_str());
        }

        TopoDS_Shape curve2;
        const Part::TopoShape& shape2 = static_cast<Part::Feature*>(c2)->Shape.getValue();
        if (!shape2._Shape.IsNull()) {
            if (shape2._Shape.ShapeType() == TopAbs_EDGE)
                curve2 = shape2._Shape;
            else
                curve2 = shape2.getSubShape(element2[0].c_str());
        }

        if (curve1.IsNull() || curve2.IsNull())
            return new App::DocumentObjectExecReturn("Linked shapes are empty.");
        if (curve1.ShapeType() == TopAbs_EDGE && curve2.ShapeType() == TopAbs_EDGE) {
            TopoDS_Face face = BRepFill::Face(TopoDS::Edge(curve1), TopoDS::Edge(curve2));
            this->Shape.setValue(face);
        }
        else if (curve1.ShapeType() == TopAbs_WIRE && curve2.ShapeType() == TopAbs_WIRE) {
            TopoDS_Shell shell = BRepFill::Shell(TopoDS::Wire(curve1), TopoDS::Wire(curve2));
            this->Shape.setValue(shell);
        }
        else {
            return new App::DocumentObjectExecReturn("Curves must either be edges or wires.");
        }
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
    catch (...) {
        return new App::DocumentObjectExecReturn("General error in RuledSurface::execute()");
    }
}

// ----------------------------------------------------------------------------

PROPERTY_SOURCE(Part::Loft, Part::Feature)

Loft::Loft()
{
    ADD_PROPERTY_TYPE(Sections,(0),"Loft",App::Prop_None,"List of sections");
    Sections.setSize(0);
    ADD_PROPERTY_TYPE(Solid,(false),"Loft",App::Prop_None,"Create solid");
    ADD_PROPERTY_TYPE(Ruled,(false),"Loft",App::Prop_None,"Ruled surface");
}

short Loft::mustExecute() const
{
    if (Sections.isTouched())
        return 1;
    if (Solid.isTouched())
        return 1;
    if (Ruled.isTouched())
        return 1;
    return 0;
}

void Loft::onChanged(const App::Property* prop)
{
    Part::Feature::onChanged(prop);
}

App::DocumentObjectExecReturn *Loft::execute(void)
{
    if (Sections.getSize() == 0)
        return new App::DocumentObjectExecReturn("No sections linked.");

    try {
        TopTools_ListOfShape profiles;
        const std::vector<App::DocumentObject*>& shapes = Sections.getValues();
        std::vector<App::DocumentObject*>::const_iterator it;
        for (it = shapes.begin(); it != shapes.end(); ++it) {
            if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId()))
                return new App::DocumentObjectExecReturn("Linked object is not a shape.");
            const TopoDS_Shape& shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
            if (shape.IsNull())
                return new App::DocumentObjectExecReturn("Linked shape is invalid.");
            if (shape.ShapeType() == TopAbs_WIRE)
                profiles.Append(shape);
            else if (shape.ShapeType() == TopAbs_VERTEX)
                profiles.Append(shape);
            else
                return new App::DocumentObjectExecReturn("Linked shape is neither a vertex nor a wire.");
        }

        Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False;
        Standard_Boolean isRuled = Ruled.getValue() ? Standard_True : Standard_False;

        TopoShape myShape;
        this->Shape.setValue(myShape.makeLoft(profiles, isSolid, isRuled));
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
}
<commit_msg>0000649: Creating a ruled surface fails<commit_after>/***************************************************************************
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRepFill.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Face.hxx>
# include <TopoDS_Shell.hxx>
#endif

#include "PartFeatures.h"

using namespace Part;

PROPERTY_SOURCE(Part::RuledSurface, Part::Feature)

RuledSurface::RuledSurface()
{
    ADD_PROPERTY_TYPE(Curve1,(0),"Ruled Surface",App::Prop_None,"Curve of ruled surface");
    ADD_PROPERTY_TYPE(Curve2,(0),"Ruled Surface",App::Prop_None,"Curve of ruled surface");
}

short RuledSurface::mustExecute() const
{
    if (Curve1.isTouched())
        return 1;
    if (Curve2.isTouched())
        return 1;
    return 0;
}

void RuledSurface::onChanged(const App::Property* prop)
{
    Part::Feature::onChanged(prop);
}

App::DocumentObjectExecReturn *RuledSurface::execute(void)
{
    try {
        App::DocumentObject* c1 = Curve1.getValue();
        if (!(c1 && c1->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
            return new App::DocumentObjectExecReturn("No shape linked.");
        const std::vector<std::string>& element1 = Curve1.getSubValues();
        if (element1.size() != 1)
            return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
        App::DocumentObject* c2 = Curve2.getValue();
        if (!(c2 && c2->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
            return new App::DocumentObjectExecReturn("No shape linked.");
        const std::vector<std::string>& element2 = Curve2.getSubValues();
        if (element2.size() != 1)
            return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");

        TopoDS_Shape curve1;
        const Part::TopoShape& shape1 = static_cast<Part::Feature*>(c1)->Shape.getValue();
        if (!shape1._Shape.IsNull()) {
            if (shape1._Shape.ShapeType() == TopAbs_EDGE)
                curve1 = shape1._Shape;
            else if (shape1._Shape.ShapeType() == TopAbs_WIRE)
                curve1 = shape1._Shape;
            else
                curve1 = shape1.getSubShape(element1[0].c_str());
        }

        TopoDS_Shape curve2;
        const Part::TopoShape& shape2 = static_cast<Part::Feature*>(c2)->Shape.getValue();
        if (!shape2._Shape.IsNull()) {
            if (shape2._Shape.ShapeType() == TopAbs_EDGE)
                curve2 = shape2._Shape;
            else if (shape2._Shape.ShapeType() == TopAbs_WIRE)
                curve2 = shape2._Shape;
            else
                curve2 = shape2.getSubShape(element2[0].c_str());
        }

        if (curve1.IsNull() || curve2.IsNull())
            return new App::DocumentObjectExecReturn("Linked shapes are empty.");
        if (curve1.ShapeType() == TopAbs_EDGE && curve2.ShapeType() == TopAbs_EDGE) {
            TopoDS_Face face = BRepFill::Face(TopoDS::Edge(curve1), TopoDS::Edge(curve2));
            this->Shape.setValue(face);
        }
        else if (curve1.ShapeType() == TopAbs_WIRE && curve2.ShapeType() == TopAbs_WIRE) {
            TopoDS_Shell shell = BRepFill::Shell(TopoDS::Wire(curve1), TopoDS::Wire(curve2));
            this->Shape.setValue(shell);
        }
        else {
            return new App::DocumentObjectExecReturn("Curves must either be edges or wires.");
        }
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
    catch (...) {
        return new App::DocumentObjectExecReturn("General error in RuledSurface::execute()");
    }
}

// ----------------------------------------------------------------------------

PROPERTY_SOURCE(Part::Loft, Part::Feature)

Loft::Loft()
{
    ADD_PROPERTY_TYPE(Sections,(0),"Loft",App::Prop_None,"List of sections");
    Sections.setSize(0);
    ADD_PROPERTY_TYPE(Solid,(false),"Loft",App::Prop_None,"Create solid");
    ADD_PROPERTY_TYPE(Ruled,(false),"Loft",App::Prop_None,"Ruled surface");
}

short Loft::mustExecute() const
{
    if (Sections.isTouched())
        return 1;
    if (Solid.isTouched())
        return 1;
    if (Ruled.isTouched())
        return 1;
    return 0;
}

void Loft::onChanged(const App::Property* prop)
{
    Part::Feature::onChanged(prop);
}

App::DocumentObjectExecReturn *Loft::execute(void)
{
    if (Sections.getSize() == 0)
        return new App::DocumentObjectExecReturn("No sections linked.");

    try {
        TopTools_ListOfShape profiles;
        const std::vector<App::DocumentObject*>& shapes = Sections.getValues();
        std::vector<App::DocumentObject*>::const_iterator it;
        for (it = shapes.begin(); it != shapes.end(); ++it) {
            if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId()))
                return new App::DocumentObjectExecReturn("Linked object is not a shape.");
            const TopoDS_Shape& shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
            if (shape.IsNull())
                return new App::DocumentObjectExecReturn("Linked shape is invalid.");
            if (shape.ShapeType() == TopAbs_WIRE)
                profiles.Append(shape);
            else if (shape.ShapeType() == TopAbs_VERTEX)
                profiles.Append(shape);
            else
                return new App::DocumentObjectExecReturn("Linked shape is neither a vertex nor a wire.");
        }

        Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False;
        Standard_Boolean isRuled = Ruled.getValue() ? Standard_True : Standard_False;

        TopoShape myShape;
        this->Shape.setValue(myShape.makeLoft(profiles, isSolid, isRuled));
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
}
<|endoftext|>


<commit_before><commit_msg>Vulkan: fix image layout validation error on Android.<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xmlnmspe.hxx,v $
 * $Revision: 1.20 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLNMSPE_HXX
#define _XMLOFF_XMLNMSPE_HXX

#include <sal/types.h>

#define XML_NAMESPACE( prefix, key ) \
const sal_uInt16 XML_NAMESPACE_##prefix         = key; \
const sal_uInt16 XML_NAMESPACE_##prefix##_IDX   = key;

#define XML_OLD_NAMESPACE( prefix, index ) \
const sal_uInt16 XML_OLD_NAMESPACE_##prefix##_IDX = \
    (_XML_OLD_NAMESPACE_BASE+index);

// current namespaces
// These namespaces have the same index in the namespace table as prefix used.
// If a namespace is added, _XML_OLD_NAMESPACE_BASE has to be adjusted!
XML_NAMESPACE( OFFICE,          0U )
XML_NAMESPACE( STYLE,           1U )
XML_NAMESPACE( TEXT ,           2U )
XML_NAMESPACE( TABLE,           3U )
XML_NAMESPACE( DRAW ,           4U )
XML_NAMESPACE( FO   ,           5U )
XML_NAMESPACE( XLINK,           6U )
XML_NAMESPACE( DC   ,           7U )
XML_NAMESPACE( META ,           8U )
XML_NAMESPACE( NUMBER,          9U )
XML_NAMESPACE( PRESENTATION,    10U )
XML_NAMESPACE( SVG,             11U )
XML_NAMESPACE( CHART,           12U )
XML_NAMESPACE( DR3D,            13U )
XML_NAMESPACE( MATH,            14U )
XML_NAMESPACE( FORM,            15U )
XML_NAMESPACE( SCRIPT,          16U )
XML_NAMESPACE( BLOCKLIST,       17U )
XML_NAMESPACE( FRAMEWORK,       18U )
XML_NAMESPACE( CONFIG,          19U )
XML_NAMESPACE( OOO,             20U )
XML_NAMESPACE( OOOW,            21U )
XML_NAMESPACE( OOOC,            22U )
XML_NAMESPACE( DOM,             23U )
XML_NAMESPACE( TCD,             24U )       // text conversion dictionary
XML_NAMESPACE( DB,              25U )
XML_NAMESPACE( DLG,             26U )
XML_NAMESPACE( XFORMS,          27U )
XML_NAMESPACE( XSD,             28U )
XML_NAMESPACE( XSI,             29U )
XML_NAMESPACE( SMIL,            30U )
XML_NAMESPACE( ANIMATION,       31U )
XML_NAMESPACE( XML,             32U )       // TODO: This 'implicit' namespace is not yet used
XML_NAMESPACE( REPORT,          33U )
XML_NAMESPACE( OF,              34U )       // OpenFormula aka ODFF

#define _XML_OLD_NAMESPACE_BASE 35U

// namespaces used in the technical preview (SO 5.2)
XML_OLD_NAMESPACE( FO,      0U )
XML_OLD_NAMESPACE( XLINK,   1U )

XML_OLD_NAMESPACE( OFFICE,  2U )
XML_OLD_NAMESPACE( STYLE,   3U )
XML_OLD_NAMESPACE( TEXT,    4U )
XML_OLD_NAMESPACE( TABLE,   5U )
XML_OLD_NAMESPACE( META,    6U )

#endif  //  _XMLOFF_XMLNMSPE_HXX
<commit_msg>INTEGRATION: CWS odfmetadata (1.20.16); FILE MERGED 2008/06/19 17:02:38 mst 1.20.16.1: #i90620#: interface change: xmloff - xmloff/inc/xmlnmspe.hxx:   + add namespace RDFA - xmloff/source/core/nmspmap.cxx:   + SvXMLNamespaceMap::GetQNameByKey(): handle the built-in XML namespace - xmloff/inc/xmloff/xmltoken.hxx, xmloff/source/core/xmltoken.cxx:   + new namespaces: XML_N_XML, XML_N_RDFA   + new token: XML_META_FIELD - xmloff/inc/xmloff/xmlimp.hxx, xmloff/source/core/xmlimp.cxx,:   + new methods GetStreamPath(), SetXmlId()   + SvXMLImport::_InitCtor():     add implicit namespace declaration for built-in "xml" prefix - xmloff/inc/xmloff/xmlexp.hxx, xmloff/source/core/xmlexp.cxx:   + new methods GetStreamPath(), AddAttributeXmlId()   + SvXMLExport::_InitCtor(): add namespace declaration for RDFA - xmloff/inc/xmloff/txtimp.hxx, xmloff/source/text/txtimp.cxx:   + XMLTextPElemTokens: add tokens: XML_TOK_TEXT_META, XML_TOK_TEXT_META_FIELD   + XMLTextPAttrTokens: add token XML_TOK_TEXT_P_XMLID   + XMLTextListBlockAttrTokens: add token XML_TOK_TEXT_LIST_BLOCK_XMLID   + InsertBookmarkStartRange(): add parameter XmlId   + FindAndRemoveBookmarkStartRange(): add parameter XmlId<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xmlnmspe.hxx,v $
 * $Revision: 1.21 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _XMLOFF_XMLNMSPE_HXX
#define _XMLOFF_XMLNMSPE_HXX

#include <sal/types.h>

#define XML_NAMESPACE( prefix, key ) \
const sal_uInt16 XML_NAMESPACE_##prefix         = key; \
const sal_uInt16 XML_NAMESPACE_##prefix##_IDX   = key;

#define XML_OLD_NAMESPACE( prefix, index ) \
const sal_uInt16 XML_OLD_NAMESPACE_##prefix##_IDX = \
    (_XML_OLD_NAMESPACE_BASE+index);

// current namespaces
// These namespaces have the same index in the namespace table as prefix used.
// If a namespace is added, _XML_OLD_NAMESPACE_BASE has to be adjusted!
XML_NAMESPACE( OFFICE,          0U )
XML_NAMESPACE( STYLE,           1U )
XML_NAMESPACE( TEXT ,           2U )
XML_NAMESPACE( TABLE,           3U )
XML_NAMESPACE( DRAW ,           4U )
XML_NAMESPACE( FO   ,           5U )
XML_NAMESPACE( XLINK,           6U )
XML_NAMESPACE( DC   ,           7U )
XML_NAMESPACE( META ,           8U )
XML_NAMESPACE( NUMBER,          9U )
XML_NAMESPACE( PRESENTATION,    10U )
XML_NAMESPACE( SVG,             11U )
XML_NAMESPACE( CHART,           12U )
XML_NAMESPACE( DR3D,            13U )
XML_NAMESPACE( MATH,            14U )
XML_NAMESPACE( FORM,            15U )
XML_NAMESPACE( SCRIPT,          16U )
XML_NAMESPACE( BLOCKLIST,       17U )
XML_NAMESPACE( FRAMEWORK,       18U )
XML_NAMESPACE( CONFIG,          19U )
XML_NAMESPACE( OOO,             20U )
XML_NAMESPACE( OOOW,            21U )
XML_NAMESPACE( OOOC,            22U )
XML_NAMESPACE( DOM,             23U )
XML_NAMESPACE( TCD,             24U )       // text conversion dictionary
XML_NAMESPACE( DB,              25U )
XML_NAMESPACE( DLG,             26U )
XML_NAMESPACE( XFORMS,          27U )
XML_NAMESPACE( XSD,             28U )
XML_NAMESPACE( XSI,             29U )
XML_NAMESPACE( SMIL,            30U )
XML_NAMESPACE( ANIMATION,       31U )
XML_NAMESPACE( XML,             32U )
XML_NAMESPACE( REPORT,          33U )
XML_NAMESPACE( OF,              34U )       // OpenFormula aka ODFF
XML_NAMESPACE( RDFA,            35U )

#define _XML_OLD_NAMESPACE_BASE 36U

// namespaces used in the technical preview (SO 5.2)
XML_OLD_NAMESPACE( FO,      0U )
XML_OLD_NAMESPACE( XLINK,   1U )

XML_OLD_NAMESPACE( OFFICE,  2U )
XML_OLD_NAMESPACE( STYLE,   3U )
XML_OLD_NAMESPACE( TEXT,    4U )
XML_OLD_NAMESPACE( TABLE,   5U )
XML_OLD_NAMESPACE( META,    6U )

#endif  //  _XMLOFF_XMLNMSPE_HXX
<|endoftext|>