<commit_before>#include "configmanip.h"

// C++
#include <cctype>

// STL
#include <map>

static inline std::string use_string(std::string& str) noexcept
{
  std::string copy;
  while(std::isspace(str.back())) // remove whitespace from end
    str.pop_back();
  copy = str;
  str.clear();
  return copy;
}

node_t::node_t(void) noexcept : type(type_e::invalid) { }
node_t::node_t(std::string& val) noexcept : type(type_e::value), value(use_string(val)) { }

std::shared_ptr<node_t> node_t::newChild(type_e t) noexcept
{
  auto& node = values.emplace(std::to_string(values.size()), std::make_shared<node_t>()).first->second;
  node->type = t;
  return node;
}

std::shared_ptr<node_t> node_t::findChild(std::string& index) const noexcept
{
  auto val = values.find(use_string(index)); // find index if it exists
  return val == values.end() ? nullptr : val->second;
}

std::shared_ptr<node_t> node_t::getChild(std::string& index) noexcept
  { return values.emplace(use_string(index), std::make_shared<node_t>()).first->second; } // insert if index does _not_ exist

root_node_t::root_node_t(void) noexcept
  : std::shared_ptr<node_t>(std::make_shared<node_t>())
  { (*this)->type = node_t::type_e::section; }

std::shared_ptr<node_t> root_node_t::findNode(std::string path) noexcept
  { return lookupNode(path, [](std::shared_ptr<node_t>& node, std::string& str) noexcept { return node->findChild(str); }); }

std::shared_ptr<node_t> root_node_t::getNode(std::string path) noexcept
  { return lookupNode(path, [](std::shared_ptr<node_t>& node, std::string& str) noexcept { return node->getChild(str); }); }

std::shared_ptr<node_t> root_node_t::lookupNode(std::string path, NodeAction func) noexcept
{
  std::shared_ptr<node_t> node = *this;
  std::string str;
  str.reserve(256);
  for(auto& letter : path)
  {
    if(node == nullptr)
      return nullptr;
    if(letter == '/')
    {
      if(str.empty())
        node = *this;
      else
        node = func(node, str);
    }
    else
      str.push_back(letter);
  }
  if(!str.empty())
    node = func(node, str);
  return node;
}

#include <cstdlib>
//constexpr
bool bailout(void)
{
  ::abort();
  return false;
}

bool ConfigManip::read(const std::string& data) noexcept
{
  enum class state_e
  {
    searching = 0, // new line
    section,       // found section
    name,          // found name
    value,         // found value
    quote,         // found opening double quotation mark
    comment,       // found semicolon outside of quotation
  };

  const char* begin = data.data();
  const char* end = begin + data.size();

  std::shared_ptr<node_t> node = nullptr;
  std::shared_ptr<node_t> section_node = nullptr;
  std::string str;
  str.reserve(4096); // values _exceeding_ 4096 bytes will likely incur a reallocation speed penalty

  state_e state = state_e::searching;
  state_e prev_state = state;

  for(const char* pos = begin; pos < end; ++pos)
  {
    if(pos[0] == '\\' && pos[1] == '\n') // line continuation feature; applicable _ANYWHERE_
    {
      ++pos;
      continue;
    }

    switch(state)
    {
      case state_e::searching:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos))
            {
              node = section_node;
              state = state_e::name;
              --pos; // moots increment
            }
            continue;

          case '[':
            node = section_node = *this;
            state = state_e::section;
            continue;

          case ']':
          case '=':
          case '"':
          case ',':
          case '\\':
            return bailout();

          case '#':
          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;
        }

      case state_e::section:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos) || !str.empty())
              str.push_back(*pos);
          case '\n':
            continue;

          case '[':
          case '=':
          case '"':
          case ',':
          case '\\':
            return bailout();

          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;

          case '/':
            if(str.empty())
              return bailout();
            node = section_node = section_node->getChild(str); // goto subsection
            continue;

          case ']':
            if(str.empty())
              return bailout();
            node = section_node = section_node->getChild(str);
            state = state_e::searching;

            switch(node->type)
            {
              case node_t::type_e::section:
              {
                std::unordered_map<std::string, std::shared_ptr<node_t>> vals = node->values;
                node->values.clear();
                node->newChild(node_t::type_e::section)->values = vals;
                node->type = node_t::type_e::multisection;
                node = section_node = node->newChild(node_t::type_e::section);
                continue;
              }

              case node_t::type_e::multisection:
                node = section_node = node->newChild(node_t::type_e::section);
                continue;

              case node_t::type_e::invalid:
                node->type = node_t::type_e::section;
                continue;

              default: // value name / section name conflict
                return bailout();
            }
        }

      case state_e::name:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos))
              str.push_back(*pos);
            continue;

          case '\n':
          case '[':
          case ']':
          case '"':
          case ',':
          case '\\':
            return bailout();

          case '=':
            node = node->getChild(str);
            state = state_e::value;
            continue;

          case '/':
            if(!str.empty()) // subsection name stored
              node = node->getChild(str);
            else if(node == section_node) // root forward slash
              node = *this;
            else // double foward slash
              return bailout();
            continue;

          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;
        }

      case state_e::value:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos) ||
               (!str.empty() &&
                !std::isspace(str.back()))) // if not a space or string doesnt end with a space
              str.push_back(*pos);
            continue;

          case '=':
            return bailout();

          case '"':
            if(!str.empty()) // if quote is in the middle of a value rather than the start of it...
              return bailout();
            prev_state = state;
            state = state_e::quote;
            continue;

          case '\n':
            if(!str.empty())
            {
              if(node->type == node_t::type_e::array) // if part of a list
                node = node->newChild(node_t::type_e::value); // make new list entry
              else
                node->type = node_t::type_e::value;
              node->value = use_string(str); // store value to current node
            }
            state = state_e::searching;
            continue;

          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;

          case ',':
            node->type = node_t::type_e::array;
            node->newChild(node_t::type_e::value)->value = use_string(str);
            continue;
        }

      case state_e::quote:
        switch(*pos)
        {
          case '"':
            state = prev_state;
            continue;
          case '\\':
            switch(*++pos)
            {
              case 'a' : str.push_back('\a'); continue;
              case 'b' : str.push_back('\b'); continue;
              case 'f' : str.push_back('\f'); continue;
              case 'n' : str.push_back('\n'); continue;
              case 'r' : str.push_back('\r'); continue;
              case 't' : str.push_back('\t'); continue;
              case 'v' : str.push_back('\v'); continue;
              case '"' : str.push_back('"' ); continue;
              case '\\': str.push_back('\\'); continue;
              default: // unrecognized escape sequence!
                return bailout();
            }
          default:
            str.push_back(*pos);
            continue;
        }

      case state_e::comment:
        switch(*pos)
        {
          case '\n':
            state = prev_state;
            --pos;
          default:
            continue;
        }
    }
  }
  return true;
}

bool write_global_node(std::shared_ptr<node_t> node, std::string section_name, std::multimap<std::string, std::string>& sections) noexcept
{
  auto section = sections.lower_bound(section_name);

  for(const std::pair<std::string, std::shared_ptr<node_t>>& entry : node->values)
  {
    switch(entry.second->type)
    {
      case node_t::type_e::value:
        section->second += entry.first + '=' + entry.second->value + '\n';
        break;

      case node_t::type_e::array:
        section->second += '\n' + entry.first + '=';
        for(auto& valnode : entry.second->values)
          section->second += valnode.second->value + ','; // concatinate into a list
        section->second.pop_back(); // remove final ','
        section->second += '\n'; // add endline
        break;

      case node_t::type_e::multisection:
      case node_t::type_e::section:
      {
        std::string subsection = section_name + '/' + entry.first;
        sections.insert(section, std::make_pair(subsection, std::string())); // create section
        write_global_node(entry.second, subsection, sections);
        break;
      }

      default:
        return false;
    }
  }
  return true;
}

bool ConfigManip::write(std::string& data) const noexcept
{
  std::multimap<std::string, std::string> sections;
  sections.insert(std::make_pair(std::string(), std::string())); // create global section

  if(!write_global_node(*this, "", sections))
    return false;
  for(const std::pair<std::string, std::string>& section : sections)
  {
    if(!section.second.empty())
    {
      if(section.first.size() > 1 && section.first.front() == '/')
        data += '[' + section.first.substr(1) + "]\n";
      data += section.second + '\n';
    }
  }
  return true;
}
<commit_msg>refactor<commit_after>#include "configmanip.h"

// C++
#include <cctype>

// STL
#include <map>

static inline std::string use_string(std::string& str) noexcept
{
  std::string copy;
  while(std::isspace(str.back())) // remove whitespace from end
    str.pop_back();
  copy = str;
  str.clear();
  return copy;
}

node_t::node_t(void) noexcept : type(type_e::invalid) { }
node_t::node_t(std::string& val) noexcept : type(type_e::value), value(use_string(val)) { }

std::shared_ptr<node_t> node_t::newChild(type_e t) noexcept
{
  auto& node = values.emplace(std::to_string(values.size()), std::make_shared<node_t>()).first->second;
  node->type = t;
  return node;
}

std::shared_ptr<node_t> node_t::findChild(std::string& index) const noexcept
{
  auto val = values.find(use_string(index)); // find index if it exists
  return val == values.end() ? nullptr : val->second;
}

std::shared_ptr<node_t> node_t::getChild(std::string& index) noexcept
  { return values.emplace(use_string(index), std::make_shared<node_t>()).first->second; } // insert if index does _not_ exist

root_node_t::root_node_t(void) noexcept
  : std::shared_ptr<node_t>(std::make_shared<node_t>())
  { (*this)->type = node_t::type_e::section; }

std::shared_ptr<node_t> root_node_t::findNode(std::string path) noexcept
  { return lookupNode(path, [](std::shared_ptr<node_t>& node, std::string& str) noexcept { return node->findChild(str); }); }

std::shared_ptr<node_t> root_node_t::getNode(std::string path) noexcept
  { return lookupNode(path, [](std::shared_ptr<node_t>& node, std::string& str) noexcept { return node->getChild(str); }); }

std::shared_ptr<node_t> root_node_t::lookupNode(std::string path, NodeAction func) noexcept
{
  std::shared_ptr<node_t> node = *this;
  std::string str;
  str.reserve(256);
  for(auto& letter : path)
  {
    if(node == nullptr)
      return nullptr;
    if(letter == '/')
    {
      if(str.empty())
        node = *this;
      else
        node = func(node, str);
    }
    else
      str.push_back(letter);
  }
  if(!str.empty())
    node = func(node, str);
  return node;
}

#include <cstdlib>
//constexpr
bool bailout(void)
{
  ::abort();
  return false;
}

bool ConfigManip::read(const std::string& data) noexcept
{
  enum class state_e
  {
    searching = 0, // new line
    section,       // found section
    name,          // found name
    value,         // found value
    quote,         // found opening double quotation mark
    comment,       // found semicolon outside of quotation
  };

  const char* begin = data.data();
  const char* end = begin + data.size();

  std::shared_ptr<node_t> node = nullptr;
  std::shared_ptr<node_t> section_node = nullptr;
  std::string str;
  str.reserve(4096); // values _exceeding_ 4096 bytes will likely incur a reallocation speed penalty

  state_e state = state_e::searching;
  state_e prev_state = state;

  for(const char* pos = begin; pos < end; ++pos)
  {
    if(pos[0] == '\\' && pos[1] == '\n') // line continuation feature; applicable _ANYWHERE_
    {
      ++pos;
      continue;
    }

    switch(state)
    {
      case state_e::searching:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos))
            {
              node = section_node;
              state = state_e::name;
              --pos; // moots increment
            }
            continue;

          case '[':
            node = section_node = *this;
            state = state_e::section;
            continue;

          case ']':
          case '=':
          case '"':
          case ',':
          case '\\':
            return bailout();

          case '#':
          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;
        }

      case state_e::section:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos) || !str.empty())
              str.push_back(*pos);
          case '\n':
            continue;

          case '[':
          case '=':
          case '"':
          case ',':
          case '\\':
            return bailout();

          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;

          case '/':
            if(str.empty())
              return bailout();
            node = section_node = section_node->getChild(str); // goto subsection
            continue;

          case ']':
            if(str.empty())
              return bailout();
            node = section_node = section_node->getChild(str);
            state = state_e::searching;

            switch(node->type)
            {
              case node_t::type_e::section:
              {
                std::unordered_map<std::string, std::shared_ptr<node_t>> vals = node->values;
                node->values.clear();
                node->newChild(node_t::type_e::section)->values = vals;
                node->type = node_t::type_e::multisection;
                node = section_node = node->newChild(node_t::type_e::section);
                continue;
              }

              case node_t::type_e::multisection:
                node = section_node = node->newChild(node_t::type_e::section);
                continue;

              case node_t::type_e::invalid:
                node->type = node_t::type_e::section;
                continue;

              default: // value name / section name conflict
                return bailout();
            }
        }

      case state_e::name:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos))
              str.push_back(*pos);
            continue;

          case '\n':
          case '[':
          case ']':
          case '"':
          case ',':
          case '\\':
            return bailout();

          case '=':
            node = node->getChild(str);
            state = state_e::value;
            continue;

          case '/':
            if(!str.empty()) // subsection name stored
              node = node->getChild(str);
            else if(node == section_node) // root forward slash
              node = *this;
            else // double foward slash
              return bailout();
            continue;

          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;
        }

      case state_e::value:
        switch(*pos)
        {
          default:
            if(!std::isspace(*pos) ||
               (!str.empty() &&
                !std::isspace(str.back()))) // if not a space or string doesnt end with a space
              str.push_back(*pos);
            continue;

          case '=':
            return bailout();

          case '"':
            if(!str.empty()) // if quote is in the middle of a value rather than the start of it...
              return bailout();
            prev_state = state;
            state = state_e::quote;
            continue;

          case '\n':
            if(!str.empty())
            {
              if(node->type == node_t::type_e::array) // if part of a list
                node = node->newChild(node_t::type_e::value); // make new list entry
              else
                node->type = node_t::type_e::value;
              node->value = use_string(str); // store value to current node
            }
            state = state_e::searching;
            continue;

          case ';':
            prev_state = state;
            state = state_e::comment;
            continue;

          case ',':
            node->type = node_t::type_e::array;
            node->newChild(node_t::type_e::value)->value = use_string(str);
            continue;
        }

      case state_e::quote:
        switch(*pos)
        {
          case '"':
            state = prev_state;
            continue;
          case '\\':
            switch(*++pos)
            {
              case 'a' : str.push_back('\a'); continue;
              case 'b' : str.push_back('\b'); continue;
              case 'f' : str.push_back('\f'); continue;
              case 'n' : str.push_back('\n'); continue;
              case 'r' : str.push_back('\r'); continue;
              case 't' : str.push_back('\t'); continue;
              case 'v' : str.push_back('\v'); continue;
              case '"' : str.push_back('"' ); continue;
              case '\\': str.push_back('\\'); continue;
              default: // unrecognized escape sequence!
                return bailout();
            }
          default:
            str.push_back(*pos);
            continue;
        }

      case state_e::comment:
        switch(*pos)
        {
          case '\n':
            state = prev_state;
            --pos;
          default:
            continue;
        }
    }
  }
  return true;
}

bool write_node(std::shared_ptr<node_t> node, std::string section_name, std::multimap<std::string, std::string>& sections) noexcept
{
  auto section = sections.lower_bound(section_name);

  for(const std::pair<std::string, std::shared_ptr<node_t>>& entry : node->values)
  {
    switch(entry.second->type)
    {
      case node_t::type_e::value:
        section->second += entry.first + '=' + entry.second->value + '\n';
        break;

      case node_t::type_e::array:
        section->second += '\n' + entry.first + '=';
        for(auto& valnode : entry.second->values)
          section->second += valnode.second->value + ','; // concatinate into a list
        section->second.pop_back(); // remove final ','
        section->second += '\n'; // add endline
        break;

      case node_t::type_e::multisection:
      case node_t::type_e::section:
      {
        std::string subsection = section_name + '/' + entry.first;
        sections.insert(section, std::make_pair(subsection, std::string())); // create section
        write_node(entry.second, subsection, sections);
        break;
      }

      default:
        return false;
    }
  }
  return true;
}

bool ConfigManip::write(std::string& data) const noexcept
{
  std::multimap<std::string, std::string> sections;
  sections.insert(std::make_pair(std::string(), std::string())); // create global section

  if(!write_node(*this, "", sections))
    return false;
  for(const std::pair<std::string, std::string>& section : sections)
  {
    if(!section.second.empty())
    {
      if(section.first.size() > 1 && section.first.front() == '/')
        data += '[' + section.first.substr(1) + "]\n";
      data += section.second + '\n';
    }
  }
  return true;
}
<|endoftext|>


<commit_before>//
//  CRTInputBufferBuilder.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 08/03/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "CRTInputBufferBuilder.hpp"
#include "CRTOpenGL.hpp"
#include <string.h>

using namespace Outputs::CRT;

CRTInputBufferBuilder::CRTInputBufferBuilder(size_t bytes_per_pixel) :
	_bytes_per_pixel(bytes_per_pixel),
	_next_write_x_position(0),
	_next_write_y_position(0),
	_image(new uint8_t[bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight])
{}

void CRTInputBufferBuilder::allocate_write_area(size_t required_length)
{
	if(_next_write_y_position != InputBufferBuilderHeight)
	{
		_last_allocation_amount = required_length;

		if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
		{
			_next_write_x_position = 0;
			_next_write_y_position++;

			if(_next_write_y_position == InputBufferBuilderHeight)
				return;
		}

		_write_x_position = _next_write_x_position + 1;
		_write_y_position = _next_write_y_position;
		_write_target_pointer = (_write_y_position * InputBufferBuilderWidth) + _write_x_position;
		_next_write_x_position += required_length + 2;
	}
}

bool CRTInputBufferBuilder::is_full()
{
	return (_next_write_y_position == InputBufferBuilderHeight);
}

void CRTInputBufferBuilder::reduce_previous_allocation_to(size_t actual_length)
{
	if(_next_write_y_position == InputBufferBuilderHeight) return;

	uint8_t *const image_pointer = _image.get();

	// correct if the writing cursor was reset while a client was writing
	if(_next_write_x_position == 0 && _next_write_y_position == 0)
	{
		memmove(&image_pointer[1], &image_pointer[_write_target_pointer], actual_length * _bytes_per_pixel);
		_write_target_pointer = 1;
		_last_allocation_amount = actual_length;
		_next_write_x_position = (uint16_t)(actual_length + 2);
	}

	// book end the allocation with duplicates of the first and last pixel, to protect
	// against rounding errors when this run is drawn
	memcpy(	&image_pointer[(_write_target_pointer - 1) * _bytes_per_pixel],
			&image_pointer[_write_target_pointer * _bytes_per_pixel],
			_bytes_per_pixel);

	memcpy(	&image_pointer[(_write_target_pointer + actual_length) * _bytes_per_pixel],
			&image_pointer[(_write_target_pointer + actual_length - 1) * _bytes_per_pixel],
			_bytes_per_pixel);

	// return any allocated length that wasn't actually used to the available pool
	_next_write_x_position -= (_last_allocation_amount - actual_length);
}

uint8_t *CRTInputBufferBuilder::get_image_pointer()
{
	return _image.get();
}

uint16_t CRTInputBufferBuilder::get_and_finalise_current_line()
{
	uint16_t result = _write_y_position + (_next_write_x_position ? 1 : 0);
	_next_write_x_position = _next_write_y_position = 0;
	return result;
}

uint8_t *CRTInputBufferBuilder::get_write_target()
{
	return (_next_write_y_position == InputBufferBuilderHeight) ? nullptr : &_image.get()[_write_target_pointer * _bytes_per_pixel];
}

uint16_t CRTInputBufferBuilder::get_last_write_x_position()
{
	return _write_x_position;
}

uint16_t CRTInputBufferBuilder::get_last_write_y_position()
{
	return _write_y_position;
}

size_t CRTInputBufferBuilder::get_bytes_per_pixel()
{
	return _bytes_per_pixel;
}
<commit_msg>Fixed: ensured that the attempt to plot a misplaced write occurs correctly.<commit_after>//
//  CRTInputBufferBuilder.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 08/03/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "CRTInputBufferBuilder.hpp"
#include "CRTOpenGL.hpp"
#include <string.h>

using namespace Outputs::CRT;

CRTInputBufferBuilder::CRTInputBufferBuilder(size_t bytes_per_pixel) :
	_bytes_per_pixel(bytes_per_pixel),
	_next_write_x_position(0),
	_next_write_y_position(0),
	_image(new uint8_t[bytes_per_pixel * InputBufferBuilderWidth * InputBufferBuilderHeight])
{}

void CRTInputBufferBuilder::allocate_write_area(size_t required_length)
{
	if(_next_write_y_position != InputBufferBuilderHeight)
	{
		_last_allocation_amount = required_length;

		if(_next_write_x_position + required_length + 2 > InputBufferBuilderWidth)
		{
			_next_write_x_position = 0;
			_next_write_y_position++;

			if(_next_write_y_position == InputBufferBuilderHeight)
				return;
		}

		_write_x_position = _next_write_x_position + 1;
		_write_y_position = _next_write_y_position;
		_write_target_pointer = (_write_y_position * InputBufferBuilderWidth) + _write_x_position;
		_next_write_x_position += required_length + 2;
	}
}

bool CRTInputBufferBuilder::is_full()
{
	return (_next_write_y_position == InputBufferBuilderHeight);
}

void CRTInputBufferBuilder::reduce_previous_allocation_to(size_t actual_length)
{
	if(_next_write_y_position == InputBufferBuilderHeight) return;

	uint8_t *const image_pointer = _image.get();

	// correct if the writing cursor was reset while a client was writing
	if(_next_write_x_position == 0 && _next_write_y_position == 0)
	{
		memmove(&image_pointer[1], &image_pointer[_write_target_pointer], actual_length * _bytes_per_pixel);
		_write_target_pointer = 1;
		_last_allocation_amount = actual_length;
		_next_write_x_position = (uint16_t)(actual_length + 2);
		_write_x_position = 1;
		_write_y_position = 0;
	}

	// book end the allocation with duplicates of the first and last pixel, to protect
	// against rounding errors when this run is drawn
	memcpy(	&image_pointer[(_write_target_pointer - 1) * _bytes_per_pixel],
			&image_pointer[_write_target_pointer * _bytes_per_pixel],
			_bytes_per_pixel);

	memcpy(	&image_pointer[(_write_target_pointer + actual_length) * _bytes_per_pixel],
			&image_pointer[(_write_target_pointer + actual_length - 1) * _bytes_per_pixel],
			_bytes_per_pixel);

	// return any allocated length that wasn't actually used to the available pool
	_next_write_x_position -= (_last_allocation_amount - actual_length);
}

uint8_t *CRTInputBufferBuilder::get_image_pointer()
{
	return _image.get();
}

uint16_t CRTInputBufferBuilder::get_and_finalise_current_line()
{
	uint16_t result = _write_y_position + (_next_write_x_position ? 1 : 0);
	_next_write_x_position = _next_write_y_position = 0;
	return result;
}

uint8_t *CRTInputBufferBuilder::get_write_target()
{
	return (_next_write_y_position == InputBufferBuilderHeight) ? nullptr : &_image.get()[_write_target_pointer * _bytes_per_pixel];
}

uint16_t CRTInputBufferBuilder::get_last_write_x_position()
{
	return _write_x_position;
}

uint16_t CRTInputBufferBuilder::get_last_write_y_position()
{
	return _write_y_position;
}

size_t CRTInputBufferBuilder::get_bytes_per_pixel()
{
	return _bytes_per_pixel;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageActor.h"

#include "vtkGraphicsFactory.h"
#include "vtkImageData.h"
#include "vtkMath.h"
#include "vtkRenderer.h"
#include "vtkTransform.h"

//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkImageActor);

//----------------------------------------------------------------------------
vtkImageActor* vtkImageActor::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkImageActor");
  return static_cast<vtkImageActor *>(ret);
}

vtkImageActor::vtkImageActor()
{
  this->Input = NULL;
  this->Interpolate = 1;
  this->Opacity = 1.0;
  this->DisplayExtent[0] = -1;
  this->DisplayExtent[1] = 0;
  this->DisplayExtent[2] = 0;
  this->DisplayExtent[3] = 0;
  this->DisplayExtent[4] = 0;
  this->DisplayExtent[5] = 0;
  this->ComputedDisplayExtent[0] = 0;
  this->ComputedDisplayExtent[1] = 0;
  this->ComputedDisplayExtent[2] = 0;
  this->ComputedDisplayExtent[3] = 0;
  this->ComputedDisplayExtent[4] = 0;
  this->ComputedDisplayExtent[5] = 0;

  vtkMath::UninitializeBounds(this->DisplayBounds);
}

vtkImageActor::~vtkImageActor()
{
  if (this->Input)
    {
    this->GetInput()->UnRegister(this);
    this->Input = NULL;
    }
}

//----------------------------------------------------------------------------
int vtkImageActor::GetSliceNumber()
{
  // find the first axis with a one pixel extent and return
  // its value

  if (this->ComputedDisplayExtent[0] == this->ComputedDisplayExtent[1])
    {
    return this->ComputedDisplayExtent[0];
    }
  if (this->ComputedDisplayExtent[2] == this->ComputedDisplayExtent[3])
    {
    return this->ComputedDisplayExtent[2];
    }
  return this->ComputedDisplayExtent[4];
}

//----------------------------------------------------------------------------
int vtkImageActor::GetSliceNumberMax()
{
  if (!this->GetInput())
    {
    return 0;
    }

  this->GetInput()->UpdateInformation();
  int *wextent = this->GetInput()->GetWholeExtent();

  // find the first axis with a one pixel extent and return
  // its value
  if (this->ComputedDisplayExtent[0] == this->ComputedDisplayExtent[1])
    {
    return wextent[1];
    }
  if (this->ComputedDisplayExtent[2] == this->ComputedDisplayExtent[3])
    {
    return wextent[3];
    }
  return wextent[5];
}

//----------------------------------------------------------------------------
int vtkImageActor::GetSliceNumberMin()
{
  if (!this->GetInput())
    {
    return 0;
    }

  this->GetInput()->UpdateInformation();
  int *wextent = this->GetInput()->GetWholeExtent();

  // find the first axis with a one pixel extent and return
  // its value
  if (this->ComputedDisplayExtent[0] == this->ComputedDisplayExtent[1])
    {
    return wextent[0];
    }
  if (this->ComputedDisplayExtent[2] == this->ComputedDisplayExtent[3])
    {
    return wextent[2];
    }
  return wextent[4];
}

//----------------------------------------------------------------------------
void vtkImageActor::SetDisplayExtent(int extent[6])
{
  int idx, modified = 0;

  for (idx = 0; idx < 6; ++idx)
    {
    if (this->DisplayExtent[idx] != extent[idx])
      {
      this->DisplayExtent[idx] = extent[idx];
      modified = 1;
      }
    }

  if (modified)
    {
    for (idx = 0; idx < 6; ++idx)
      {
      this->ComputedDisplayExtent[idx] = extent[idx];
      }
    this->Modified();
    }
}
//----------------------------------------------------------------------------
void vtkImageActor::SetDisplayExtent(int minX, int maxX,
                                     int minY, int maxY,
                                     int minZ, int maxZ)
{
  int extent[6];

  extent[0] = minX;  extent[1] = maxX;
  extent[2] = minY;  extent[3] = maxY;
  extent[4] = minZ;  extent[5] = maxZ;
  this->SetDisplayExtent(extent);
}

//----------------------------------------------------------------------------
void vtkImageActor::GetDisplayExtent(int extent[6])
{
  int idx;

  for (idx = 0; idx < 6; ++idx)
    {
    extent[idx] = this->DisplayExtent[idx];
    }
}

//-----------------------------------------------------------------------------
// Renders an actor2D's property and then it's mapper.
int vtkImageActor::RenderTranslucentPolygonalGeometry(vtkViewport* viewport)
{
  vtkDebugMacro(<< "vtkImageActor::RenderTranslucentPolygonalGeometry");

  vtkImageData *input = this->GetInput();
  if (!input)
    {
    return 0;
    }

  // render the texture map
  if ( input->GetScalarType() == VTK_UNSIGNED_CHAR )
    {
    if (!(this->Opacity >= 1.0 && input->GetNumberOfScalarComponents() % 2))
      {
      this->Render(vtkRenderer::SafeDownCast(viewport));
      return 1;
      }
    }

  return 0;
}

//-----------------------------------------------------------------------------
// Description:
// Does this prop have some translucent polygonal geometry?
int vtkImageActor::HasTranslucentPolygonalGeometry()
{
  vtkImageData *input = this->GetInput();
  if (!input)
    {
    return 0;
    }

  // render the texture map
  if ( input->GetScalarType() == VTK_UNSIGNED_CHAR )
    {
    if (!(this->Opacity >= 1.0 && input->GetNumberOfScalarComponents() % 2))
      {
      return 1;
      }
    }

  return 0;
}

//-----------------------------------------------------------------------------
int vtkImageActor::RenderOpaqueGeometry(vtkViewport* viewport)
{
  vtkDebugMacro(<< "vtkImageActor::RenderOpaqueGeometry");

  vtkImageData *input = this->GetInput();
  if (!input)
    {
    return 0;
    }
  // make sure the data is available
  input->UpdateInformation();

  // if the display extent has not been set, then compute one
  int *wExtent = input->GetWholeExtent();
  if (this->DisplayExtent[0] == -1)
    {
    this->ComputedDisplayExtent[0] = wExtent[0];
    this->ComputedDisplayExtent[1] = wExtent[1];
    this->ComputedDisplayExtent[2] = wExtent[2];
    this->ComputedDisplayExtent[3] = wExtent[3];
    this->ComputedDisplayExtent[4] = wExtent[4];
    this->ComputedDisplayExtent[5] = wExtent[4];
    }
  input->SetUpdateExtent(this->ComputedDisplayExtent);
  input->PropagateUpdateExtent();
  input->UpdateData();

  // render the texture map
  if ( input->GetScalarType() == VTK_UNSIGNED_CHAR )
    {
    if (this->Opacity >= 1.0 && input->GetNumberOfScalarComponents() % 2)
      {
      this->Render(vtkRenderer::SafeDownCast(viewport));
      return 1;
      }
    }
  else
    {
    vtkErrorMacro(<<"This filter requires unsigned char scalars as input");
    }

  return 0;
}

// Get the bounds for this Volume as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
double *vtkImageActor::GetDisplayBounds()
{
  if (!this->Input)
    {
    return this->DisplayBounds;
    }
  this->Input->UpdateInformation();
  double *spacing = this->Input->GetSpacing();
  double *origin = this->Input->GetOrigin();

  // if the display extent has not been set, then compute one
  int *wExtent = this->Input->GetWholeExtent();
  if (this->DisplayExtent[0] == -1)
    {
    this->ComputedDisplayExtent[0] = wExtent[0];
    this->ComputedDisplayExtent[1] = wExtent[1];
    this->ComputedDisplayExtent[2] = wExtent[2];
    this->ComputedDisplayExtent[3] = wExtent[3];
    this->ComputedDisplayExtent[4] = wExtent[4];
    this->ComputedDisplayExtent[5] = wExtent[4];
    }
  if (spacing[0] >= 0)
    {
    this->DisplayBounds[0] =
      this->ComputedDisplayExtent[0]*spacing[0] + origin[0];
    this->DisplayBounds[1] =
      this->ComputedDisplayExtent[1]*spacing[0] + origin[0];
    }
  else
    {
    this->DisplayBounds[0] =
      this->ComputedDisplayExtent[1]*spacing[0] + origin[0];
    this->DisplayBounds[1] =
      this->ComputedDisplayExtent[0]*spacing[0] + origin[0];
    }
  if (spacing[1] >= 0)
    {
    this->DisplayBounds[2] =
      this->ComputedDisplayExtent[2]*spacing[1] + origin[1];
    this->DisplayBounds[3] =
      this->ComputedDisplayExtent[3]*spacing[1] + origin[1];
    }
  else
    {
    this->DisplayBounds[2] =
      this->ComputedDisplayExtent[3]*spacing[1] + origin[1];
    this->DisplayBounds[3] =
      this->ComputedDisplayExtent[2]*spacing[1] + origin[1];
    }
  if (spacing[2] >= 0)
    {
    this->DisplayBounds[4] =
      this->ComputedDisplayExtent[4]*spacing[2] + origin[2];
    this->DisplayBounds[5] =
      this->ComputedDisplayExtent[5]*spacing[2] + origin[2];
    }
  else
    {
    this->DisplayBounds[4] =
      this->ComputedDisplayExtent[5]*spacing[2] + origin[2];
    this->DisplayBounds[5] =
      this->ComputedDisplayExtent[4]*spacing[2] + origin[2];
    }

  return this->DisplayBounds;
}

// Get the bounds for the displayed data as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
void vtkImageActor::GetDisplayBounds(double bounds[6])
{
  this->GetDisplayBounds();
  for (int i=0; i<6; i++)
    {
    bounds[i] = this->DisplayBounds[i];
    }
}

// Get the bounds for this Prop3D as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
double *vtkImageActor::GetBounds()
{
  int i,n;
  double *bounds, bbox[24], *fptr;

  bounds = this->GetDisplayBounds();
  // Check for the special case when the data bounds are unknown
  if (!bounds)
    {
    return bounds;
    }

  // fill out vertices of a bounding box
  bbox[ 0] = bounds[1]; bbox[ 1] = bounds[3]; bbox[ 2] = bounds[5];
  bbox[ 3] = bounds[1]; bbox[ 4] = bounds[2]; bbox[ 5] = bounds[5];
  bbox[ 6] = bounds[0]; bbox[ 7] = bounds[2]; bbox[ 8] = bounds[5];
  bbox[ 9] = bounds[0]; bbox[10] = bounds[3]; bbox[11] = bounds[5];
  bbox[12] = bounds[1]; bbox[13] = bounds[3]; bbox[14] = bounds[4];
  bbox[15] = bounds[1]; bbox[16] = bounds[2]; bbox[17] = bounds[4];
  bbox[18] = bounds[0]; bbox[19] = bounds[2]; bbox[20] = bounds[4];
  bbox[21] = bounds[0]; bbox[22] = bounds[3]; bbox[23] = bounds[4];

  // save the old transform
  this->Transform->Push();
  this->Transform->SetMatrix(this->GetMatrix());

  // and transform into actors coordinates
  fptr = bbox;
  for (n = 0; n < 8; n++)
    {
    this->Transform->TransformPoint(fptr,fptr);
    fptr += 3;
    }

  this->Transform->Pop();

  // now calc the new bounds
  this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = VTK_DOUBLE_MAX;
  this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = -VTK_DOUBLE_MAX;
  for (i = 0; i < 8; i++)
    {
    for (n = 0; n < 3; n++)
      {
      if (bbox[i*3+n] < this->Bounds[n*2])
        {
        this->Bounds[n*2] = bbox[i*3+n];
        }
      if (bbox[i*3+n] > this->Bounds[n*2+1])
        {
        this->Bounds[n*2+1] = bbox[i*3+n];
        }
      }
    }

  return this->Bounds;
}

void vtkImageActor::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "Input: " << this->Input << "\n";
  os << indent << "Interpolate: " << (this->Interpolate ? "On\n" : "Off\n");
  os << indent << "Opacity: " << this->Opacity << "\n";

  int idx;
  os << indent << "DisplayExtent: (" << this->DisplayExtent[0];
  for (idx = 1; idx < 6; ++idx)
    {
    os << ", " << this->DisplayExtent[idx];
    }
  os << ")\n";
}

//----------------------------------------------------------------------------
int vtkImageActor::GetWholeZMin()
{
  int *extent;

  if ( ! this->GetInput())
    {
    return 0;
    }
  this->GetInput()->UpdateInformation();
  extent = this->GetInput()->GetWholeExtent();
  return extent[4];
}

//----------------------------------------------------------------------------
int vtkImageActor::GetWholeZMax()
{
  int *extent;

  if ( ! this->GetInput())
    {
    return 0;
    }
  this->GetInput()->UpdateInformation();
  extent = this->GetInput()->GetWholeExtent();
  return extent[5];
}

void vtkImageActor::SetInput(vtkImageData *args)
{
  vtkDebugMacro(<< this->GetClassName() << " (" << this
  << "): setting Input to " << args );
  if (this->Input != args)
    {
    if (this->Input != NULL)
      {
      this->Input->UnRegister(this);
      }
    this->Input = args;
    if (this->Input != NULL)
      {
      this->Input->Register(this);
      }
    this->Modified();
    }
}

<commit_msg>BUG: Fix copy paste bug that was setting the wrong extents.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageActor.h"

#include "vtkGraphicsFactory.h"
#include "vtkImageData.h"
#include "vtkMath.h"
#include "vtkRenderer.h"
#include "vtkTransform.h"

//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkImageActor);

//----------------------------------------------------------------------------
vtkImageActor* vtkImageActor::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkImageActor");
  return static_cast<vtkImageActor *>(ret);
}

vtkImageActor::vtkImageActor()
{
  this->Input = NULL;
  this->Interpolate = 1;
  this->Opacity = 1.0;
  this->DisplayExtent[0] = -1;
  this->DisplayExtent[1] = 0;
  this->DisplayExtent[2] = 0;
  this->DisplayExtent[3] = 0;
  this->DisplayExtent[4] = 0;
  this->DisplayExtent[5] = 0;
  this->ComputedDisplayExtent[0] = 0;
  this->ComputedDisplayExtent[1] = 0;
  this->ComputedDisplayExtent[2] = 0;
  this->ComputedDisplayExtent[3] = 0;
  this->ComputedDisplayExtent[4] = 0;
  this->ComputedDisplayExtent[5] = 0;

  vtkMath::UninitializeBounds(this->DisplayBounds);
}

vtkImageActor::~vtkImageActor()
{
  if (this->Input)
    {
    this->GetInput()->UnRegister(this);
    this->Input = NULL;
    }
}

//----------------------------------------------------------------------------
int vtkImageActor::GetSliceNumber()
{
  // find the first axis with a one pixel extent and return
  // its value

  if (this->ComputedDisplayExtent[0] == this->ComputedDisplayExtent[1])
    {
    return this->ComputedDisplayExtent[0];
    }
  if (this->ComputedDisplayExtent[2] == this->ComputedDisplayExtent[3])
    {
    return this->ComputedDisplayExtent[2];
    }
  return this->ComputedDisplayExtent[4];
}

//----------------------------------------------------------------------------
int vtkImageActor::GetSliceNumberMax()
{
  if (!this->GetInput())
    {
    return 0;
    }

  this->GetInput()->UpdateInformation();
  int *wextent = this->GetInput()->GetWholeExtent();

  // find the first axis with a one pixel extent and return
  // its value
  if (this->ComputedDisplayExtent[0] == this->ComputedDisplayExtent[1])
    {
    return wextent[1];
    }
  if (this->ComputedDisplayExtent[2] == this->ComputedDisplayExtent[3])
    {
    return wextent[3];
    }
  return wextent[5];
}

//----------------------------------------------------------------------------
int vtkImageActor::GetSliceNumberMin()
{
  if (!this->GetInput())
    {
    return 0;
    }

  this->GetInput()->UpdateInformation();
  int *wextent = this->GetInput()->GetWholeExtent();

  // find the first axis with a one pixel extent and return
  // its value
  if (this->ComputedDisplayExtent[0] == this->ComputedDisplayExtent[1])
    {
    return wextent[0];
    }
  if (this->ComputedDisplayExtent[2] == this->ComputedDisplayExtent[3])
    {
    return wextent[2];
    }
  return wextent[4];
}

//----------------------------------------------------------------------------
void vtkImageActor::SetDisplayExtent(int extent[6])
{
  int idx, modified = 0;

  for (idx = 0; idx < 6; ++idx)
    {
    if (this->DisplayExtent[idx] != extent[idx])
      {
      this->DisplayExtent[idx] = extent[idx];
      modified = 1;
      }
    }

  if (modified)
    {
    for (idx = 0; idx < 6; ++idx)
      {
      this->ComputedDisplayExtent[idx] = extent[idx];
      }
    this->Modified();
    }
}
//----------------------------------------------------------------------------
void vtkImageActor::SetDisplayExtent(int minX, int maxX,
                                     int minY, int maxY,
                                     int minZ, int maxZ)
{
  int extent[6];

  extent[0] = minX;  extent[1] = maxX;
  extent[2] = minY;  extent[3] = maxY;
  extent[4] = minZ;  extent[5] = maxZ;
  this->SetDisplayExtent(extent);
}

//----------------------------------------------------------------------------
void vtkImageActor::GetDisplayExtent(int extent[6])
{
  int idx;

  for (idx = 0; idx < 6; ++idx)
    {
    extent[idx] = this->DisplayExtent[idx];
    }
}

//-----------------------------------------------------------------------------
// Renders an actor2D's property and then it's mapper.
int vtkImageActor::RenderTranslucentPolygonalGeometry(vtkViewport* viewport)
{
  vtkDebugMacro(<< "vtkImageActor::RenderTranslucentPolygonalGeometry");

  vtkImageData *input = this->GetInput();
  if (!input)
    {
    return 0;
    }

  // render the texture map
  if ( input->GetScalarType() == VTK_UNSIGNED_CHAR )
    {
    if (!(this->Opacity >= 1.0 && input->GetNumberOfScalarComponents() % 2))
      {
      this->Render(vtkRenderer::SafeDownCast(viewport));
      return 1;
      }
    }

  return 0;
}

//-----------------------------------------------------------------------------
// Description:
// Does this prop have some translucent polygonal geometry?
int vtkImageActor::HasTranslucentPolygonalGeometry()
{
  vtkImageData *input = this->GetInput();
  if (!input)
    {
    return 0;
    }

  // render the texture map
  if ( input->GetScalarType() == VTK_UNSIGNED_CHAR )
    {
    if (!(this->Opacity >= 1.0 && input->GetNumberOfScalarComponents() % 2))
      {
      return 1;
      }
    }

  return 0;
}

//-----------------------------------------------------------------------------
int vtkImageActor::RenderOpaqueGeometry(vtkViewport* viewport)
{
  vtkDebugMacro(<< "vtkImageActor::RenderOpaqueGeometry");

  vtkImageData *input = this->GetInput();
  if (!input)
    {
    return 0;
    }
  // make sure the data is available
  input->UpdateInformation();

  // if the display extent has not been set, then compute one
  int *wExtent = input->GetWholeExtent();
  if (this->DisplayExtent[0] == -1)
    {
    this->ComputedDisplayExtent[0] = wExtent[0];
    this->ComputedDisplayExtent[1] = wExtent[1];
    this->ComputedDisplayExtent[2] = wExtent[2];
    this->ComputedDisplayExtent[3] = wExtent[3];
    this->ComputedDisplayExtent[4] = wExtent[4];
    this->ComputedDisplayExtent[5] = wExtent[5];
    }
  input->SetUpdateExtent(this->ComputedDisplayExtent);
  input->PropagateUpdateExtent();
  input->UpdateData();

  // render the texture map
  if ( input->GetScalarType() == VTK_UNSIGNED_CHAR )
    {
    if (this->Opacity >= 1.0 && input->GetNumberOfScalarComponents() % 2)
      {
      this->Render(vtkRenderer::SafeDownCast(viewport));
      return 1;
      }
    }
  else
    {
    vtkErrorMacro(<<"This filter requires unsigned char scalars as input");
    }

  return 0;
}

// Get the bounds for this Volume as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
double *vtkImageActor::GetDisplayBounds()
{
  if (!this->Input)
    {
    return this->DisplayBounds;
    }
  this->Input->UpdateInformation();
  double *spacing = this->Input->GetSpacing();
  double *origin = this->Input->GetOrigin();

  // if the display extent has not been set, then compute one
  int *wExtent = this->Input->GetWholeExtent();
  if (this->DisplayExtent[0] == -1)
    {
    this->ComputedDisplayExtent[0] = wExtent[0];
    this->ComputedDisplayExtent[1] = wExtent[1];
    this->ComputedDisplayExtent[2] = wExtent[2];
    this->ComputedDisplayExtent[3] = wExtent[3];
    this->ComputedDisplayExtent[4] = wExtent[4];
    this->ComputedDisplayExtent[5] = wExtent[5];
    }
  if (spacing[0] >= 0)
    {
    this->DisplayBounds[0] =
      this->ComputedDisplayExtent[0]*spacing[0] + origin[0];
    this->DisplayBounds[1] =
      this->ComputedDisplayExtent[1]*spacing[0] + origin[0];
    }
  else
    {
    this->DisplayBounds[0] =
      this->ComputedDisplayExtent[1]*spacing[0] + origin[0];
    this->DisplayBounds[1] =
      this->ComputedDisplayExtent[0]*spacing[0] + origin[0];
    }
  if (spacing[1] >= 0)
    {
    this->DisplayBounds[2] =
      this->ComputedDisplayExtent[2]*spacing[1] + origin[1];
    this->DisplayBounds[3] =
      this->ComputedDisplayExtent[3]*spacing[1] + origin[1];
    }
  else
    {
    this->DisplayBounds[2] =
      this->ComputedDisplayExtent[3]*spacing[1] + origin[1];
    this->DisplayBounds[3] =
      this->ComputedDisplayExtent[2]*spacing[1] + origin[1];
    }
  if (spacing[2] >= 0)
    {
    this->DisplayBounds[4] =
      this->ComputedDisplayExtent[4]*spacing[2] + origin[2];
    this->DisplayBounds[5] =
      this->ComputedDisplayExtent[5]*spacing[2] + origin[2];
    }
  else
    {
    this->DisplayBounds[4] =
      this->ComputedDisplayExtent[5]*spacing[2] + origin[2];
    this->DisplayBounds[5] =
      this->ComputedDisplayExtent[4]*spacing[2] + origin[2];
    }

  return this->DisplayBounds;
}

// Get the bounds for the displayed data as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
void vtkImageActor::GetDisplayBounds(double bounds[6])
{
  this->GetDisplayBounds();
  for (int i=0; i<6; i++)
    {
    bounds[i] = this->DisplayBounds[i];
    }
}

// Get the bounds for this Prop3D as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
double *vtkImageActor::GetBounds()
{
  int i,n;
  double *bounds, bbox[24], *fptr;

  bounds = this->GetDisplayBounds();
  // Check for the special case when the data bounds are unknown
  if (!bounds)
    {
    return bounds;
    }

  // fill out vertices of a bounding box
  bbox[ 0] = bounds[1]; bbox[ 1] = bounds[3]; bbox[ 2] = bounds[5];
  bbox[ 3] = bounds[1]; bbox[ 4] = bounds[2]; bbox[ 5] = bounds[5];
  bbox[ 6] = bounds[0]; bbox[ 7] = bounds[2]; bbox[ 8] = bounds[5];
  bbox[ 9] = bounds[0]; bbox[10] = bounds[3]; bbox[11] = bounds[5];
  bbox[12] = bounds[1]; bbox[13] = bounds[3]; bbox[14] = bounds[4];
  bbox[15] = bounds[1]; bbox[16] = bounds[2]; bbox[17] = bounds[4];
  bbox[18] = bounds[0]; bbox[19] = bounds[2]; bbox[20] = bounds[4];
  bbox[21] = bounds[0]; bbox[22] = bounds[3]; bbox[23] = bounds[4];

  // save the old transform
  this->Transform->Push();
  this->Transform->SetMatrix(this->GetMatrix());

  // and transform into actors coordinates
  fptr = bbox;
  for (n = 0; n < 8; n++)
    {
    this->Transform->TransformPoint(fptr,fptr);
    fptr += 3;
    }

  this->Transform->Pop();

  // now calc the new bounds
  this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = VTK_DOUBLE_MAX;
  this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = -VTK_DOUBLE_MAX;
  for (i = 0; i < 8; i++)
    {
    for (n = 0; n < 3; n++)
      {
      if (bbox[i*3+n] < this->Bounds[n*2])
        {
        this->Bounds[n*2] = bbox[i*3+n];
        }
      if (bbox[i*3+n] > this->Bounds[n*2+1])
        {
        this->Bounds[n*2+1] = bbox[i*3+n];
        }
      }
    }

  return this->Bounds;
}

void vtkImageActor::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "Input: " << this->Input << "\n";
  os << indent << "Interpolate: " << (this->Interpolate ? "On\n" : "Off\n");
  os << indent << "Opacity: " << this->Opacity << "\n";

  int idx;
  os << indent << "DisplayExtent: (" << this->DisplayExtent[0];
  for (idx = 1; idx < 6; ++idx)
    {
    os << ", " << this->DisplayExtent[idx];
    }
  os << ")\n";
}

//----------------------------------------------------------------------------
int vtkImageActor::GetWholeZMin()
{
  int *extent;

  if ( ! this->GetInput())
    {
    return 0;
    }
  this->GetInput()->UpdateInformation();
  extent = this->GetInput()->GetWholeExtent();
  return extent[4];
}

//----------------------------------------------------------------------------
int vtkImageActor::GetWholeZMax()
{
  int *extent;

  if ( ! this->GetInput())
    {
    return 0;
    }
  this->GetInput()->UpdateInformation();
  extent = this->GetInput()->GetWholeExtent();
  return extent[5];
}

void vtkImageActor::SetInput(vtkImageData *args)
{
  vtkDebugMacro(<< this->GetClassName() << " (" << this
  << "): setting Input to " << args );
  if (this->Input != args)
    {
    if (this->Input != NULL)
      {
      this->Input->UnRegister(this);
      }
    this->Input = args;
    if (this->Input != NULL)
      {
      this->Input->Register(this);
      }
    this->Modified();
    }
}

<|endoftext|>


<commit_before>#include "action_header.h"
#include "../server_settings.h"
#include "../ClientMain.h"

namespace
{
	void access_dir_details(std::string folder, std::string& ret)
	{
		bool has_error = false;
		getFiles(folder, &has_error);
		if (has_error)
		{
			ret += "Cannot access " + folder + ". " + os_last_error_str() + "\n";
		}
		else
		{
			ret += "Can access " + folder + "\n";
		}
	}

	std::string access_err_details(std::string folder)
	{
		std::vector<std::string> toks;
		Tokenize(folder, toks, os_file_sep());

		std::string ret;

		std::string cdir = os_file_sep();
		access_dir_details(cdir, ret);

		for (size_t i = 0; i < toks.size(); ++i)
		{
			if (toks[i].empty()) continue;

			if (cdir != os_file_sep())
			{
				cdir += os_file_sep();
			}
			cdir += toks[i];

			access_dir_details(cdir, ret);
		}

		return ret;
	}

	std::string access_dir_hint(std::string folder)
	{
		if (folder.size() > 1 && folder[1] == ':')
		{
			bool has_error = false;
			getFiles(folder.substr(0, 2) + os_file_sep(), &has_error);

			if (has_error)
			{
				return "volume_not_accessible";
			}
		}

		if ((folder.size() > 2 && folder[0] == '\\'
			&& folder[1] == '\\'
			&& folder[2] != '?')
			|| next(folder, 0, "\\\\?\\UNC"))
		{
			bool has_error = false;
			getFiles(folder, &has_error);

			if (has_error && os_last_error() == 5
				|| os_last_error() == 1326)
			{
				return "folder_unc_access_denied";
			}
		}

		return std::string();
	}

	bool is_stop_show(IDatabase* db, std::string stop_key)
	{
		db_results res = db->Read("SELECT tvalue FROM misc WHERE tkey='stop_show'");
		if (!res.empty())
		{
			std::vector<std::string> toks;
			Tokenize(res[0]["tvalue"], toks, ",");
			return std::find(toks.begin(), toks.end(), stop_key) != toks.end();
		}
		return false;
	}

	void add_stop_show(IDatabase* db, JSON::Object& ret, std::string dir_error_stop_show_key)
	{
		ret.set("dir_error_stop_show_key", dir_error_stop_show_key);
		if (is_stop_show(db, dir_error_stop_show_key))
		{
			ret.set("dir_error_show", false);
		}
	}

	void access_dir_checks(IDatabase* db, ServerSettings& settings, std::string backupfolder, std::string backupfolder_uncompr,
		JSON::Object& ret)
	{
#ifdef _WIN32
		if (backupfolder.size() == 2 && backupfolder[1] == ':')
		{
			backupfolder += os_file_sep();
		}
		if (backupfolder_uncompr.size() == 2 && backupfolder_uncompr[1] == ':')
		{
			backupfolder_uncompr += os_file_sep();
		}
#endif

		if (backupfolder.empty() || !os_directory_exists(os_file_prefix(backupfolder)) || !os_directory_exists(os_file_prefix(backupfolder_uncompr)))
		{
			if (!backupfolder.empty())
			{
				ret.set("system_err", os_last_error_str());
			}

			ret.set("dir_error", true);

			if (settings.getSettings()->backupfolder.empty())
			{
				ret.set("dir_error_ext", "err_name_empty");
			}
			else if (!os_directory_exists(os_file_prefix(settings.getSettings()->backupfolder)))
			{
				ret.set("dir_error_ext", "err_folder_not_found");
				add_stop_show(db, ret, "dir_error_not_found");
			}
			else
			{
				add_stop_show(db, ret, "dir_error_misc");
			}

#ifdef _WIN32
			std::string hint = access_dir_hint(settings.getSettings()->backupfolder);
			if (!hint.empty())
			{
				ret.set("dir_error_hint", hint);
			}
#endif

#ifndef _WIN32
			ret.set("detail_err_str", access_err_details(settings.getSettings()->backupfolder));
#endif
		}
		else if (!os_directory_exists(os_file_prefix(backupfolder + os_file_sep() + "clients")) && !os_create_dir(os_file_prefix(backupfolder + os_file_sep() + "clients")))
		{
			ret.set("system_err", os_last_error_str());
			ret.set("dir_error", true);
			ret.set("dir_error_ext", "err_cannot_create_subdir");

			add_stop_show(db, ret, "dir_error_cannot_create_subdir");

#ifdef _WIN32
			std::string hint = access_dir_hint(backupfolder);
			if (!hint.empty())
			{
				ret.set("dir_error_hint", hint);
			}
#endif
		}
		else
		{
			bool has_access_error = false;
			std::string testfoldername = "testfolderHvfgh---dFFoeRRRf";
			std::string testfolderpath = backupfolder + os_file_sep() + testfoldername;
			if (os_directory_exists(os_file_prefix(testfolderpath)))
			{
				if (!os_remove_dir(os_file_prefix(testfolderpath)))
				{
					ret.set("system_err", os_last_error_str());
					ret.set("dir_error", true);
					ret.set("dir_error_ext", "err_cannot_create_subdir");
					add_stop_show(db, ret, "dir_error_cannot_create_subdir2");
					has_access_error = true;
#ifdef _WIN32
					std::string hint = access_dir_hint(backupfolder);
					if (!hint.empty())
					{
						ret.set("dir_error_hint", hint);
					}
#endif
				}
			}

			SSettings* server_settings = settings.getSettings();

			if (!has_access_error
				&& !os_create_dir(os_file_prefix(testfolderpath)))
			{
				ret.set("system_err", os_last_error_str());
				ret.set("dir_error", true);
				ret.set("dir_error_ext", "err_cannot_create_subdir");
				add_stop_show(db, ret, "dir_error_cannot_create_subdir3");

#ifdef _WIN32
				std::string hint = access_dir_hint(backupfolder);
				if (!hint.empty())
				{
					ret.set("dir_error_hint", hint);
				}
#endif
				has_access_error = true;
			}
#ifdef _WIN32
			else if (!server_settings->no_file_backups
				&& os_directory_exists(os_file_prefix(backupfolder + os_file_sep() + "testfo~1")))
			{
				ret.set("dir_error", true);
				ret.set("dir_error_ext", "dos_names_created");
				add_stop_show(db, ret, "dos_names_created");
				ret.set("dir_error_hint", "dos_names_created");
				if (backupfolder.size() > 2
					&& backupfolder[1] == ':')
				{
					ret.set("dir_error_volume", backupfolder.substr(0, 2));
				}
				else
				{
					ret.set("dir_error_volume", "<VOLUME>");
				}
			}
#endif

			if (!server_settings->no_file_backups)
			{
				std::string linkfolderpath = testfolderpath + "_link";
				os_remove_symlink_dir(os_file_prefix(linkfolderpath));
				Server->deleteFile(os_file_prefix(linkfolderpath));

				if (!has_access_error
					&& !os_link_symbolic(os_file_prefix(testfolderpath), os_file_prefix(linkfolderpath)))
				{
					ret.set("system_err", os_last_error_str());
					ret.set("dir_error", true);
					ret.set("dir_error_ext", "err_cannot_create_symbolic_links");
					ret.set("dir_error_hint", "UrBackup cannot create symbolic links on the backup storage. "
						"Your backup storage must support symbolic links in order for UrBackup to work correctly. "
						"The UrBackup Server must run as administrative user on Windows (If not you get error code 1314). "
						"Note: As of 2016-05-07 samba (which is used by many Linux based NAS operating systems for Windows file sharing) has not "
						"implemented the necessary functionality to support symbolic link creation from Windows (With this you get error code 4390).");
					add_stop_show(db, ret, "dir_error_cannot_create_symbolic_links");
				}

				os_remove_symlink_dir(os_file_prefix(linkfolderpath));
			}

			if (!server_settings->no_file_backups)
			{
				bool use_tmpfiles = server_settings->use_tmpfiles;
				std::string tmpfile_path;
				if (!use_tmpfiles)
				{
					tmpfile_path = server_settings->backupfolder + os_file_sep() + "urbackup_tmp_files";
				}

				std::auto_ptr<IFile> tmp_f(ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, logid_t()));

				if (tmp_f.get() == NULL)
				{
					ret.set("tmpdir_error", true);
					ret.set("tmpdir_error_stop_show_key", "tmpdir_error");
					if (is_stop_show(db, "tmpdir_error"))
					{
						ret.set("tmpdir_error_show", false);
					}
				}
				else
				{
					std::string teststring = base64_decode("WDVPIVAlQEFQWzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCo=");
					tmp_f->Write(teststring);
					std::string tmp_fn = tmp_f->getFilename();
					tmp_f.reset();
					tmp_f.reset(Server->openFile(tmp_fn, MODE_RW));

					std::string readstring;
					if (tmp_f.get() != NULL)
					{
						readstring = tmp_f->Read(static_cast<_u32>(teststring.size()));
					}

					tmp_f.reset();
					Server->deleteFile(tmp_fn);

					if (teststring != readstring)
					{
						ret.set("virus_error", true);
						ret.set("virus_error_path", ExtractFilePath(tmp_fn));
						ret.set("virus_error_stop_show_key", "virus_error");
						if (is_stop_show(db, "virus_error"))
						{
							ret.set("virus_error_show", false);
						}
					}
				}
			}

			if (!has_access_error
				&& !os_remove_dir(os_file_prefix(testfolderpath)))
			{
				ret.set("system_err", os_last_error_str());
				ret.set("dir_error", true);
				ret.set("dir_error_ext", "err_cannot_create_subdir");
				add_stop_show(db, ret, "dir_error_cannot_create_subdir4");
				has_access_error = true;
			}
		}

		IFile *tmp = Server->openTemporaryFile();
		ScopedDeleteFile delete_tmp_file(tmp);
		if (tmp == NULL)
		{
			ret.set("tmpdir_error", true);
			ret.set("tmpdir_error_stop_show_key", "tmpdir_error");
			if (is_stop_show(db, "tmpdir_error"))
			{
				ret.set("tmpdir_error_show", false);
			}
		}
	}
}

ACTION_IMPL(status_check)
{
	Helper helper(tid, &POST, &PARAMS);
	JSON::Object ret;

	std::string rights = helper.getRights("status");
	SUser *session = helper.getSession();
	if (session != NULL && session->id == SESSION_ID_INVALID) return;
	if (session != NULL && rights == "all")
	{
		IDatabase *db = helper.getDatabase();
		ServerSettings settings(db);
		access_dir_checks(db, settings, settings.getSettings()->backupfolder,
			settings.getSettings()->backupfolder_uncompr, ret);
	}
	else
	{
		ret.set("error", 1);
	}
	helper.Write(ret.stringify(false));
}<commit_msg>Release session when doing access dir checks<commit_after>#include "action_header.h"
#include "../server_settings.h"
#include "../ClientMain.h"

namespace
{
	void access_dir_details(std::string folder, std::string& ret)
	{
		bool has_error = false;
		getFiles(folder, &has_error);
		if (has_error)
		{
			ret += "Cannot access " + folder + ". " + os_last_error_str() + "\n";
		}
		else
		{
			ret += "Can access " + folder + "\n";
		}
	}

	std::string access_err_details(std::string folder)
	{
		std::vector<std::string> toks;
		Tokenize(folder, toks, os_file_sep());

		std::string ret;

		std::string cdir = os_file_sep();
		access_dir_details(cdir, ret);

		for (size_t i = 0; i < toks.size(); ++i)
		{
			if (toks[i].empty()) continue;

			if (cdir != os_file_sep())
			{
				cdir += os_file_sep();
			}
			cdir += toks[i];

			access_dir_details(cdir, ret);
		}

		return ret;
	}

	std::string access_dir_hint(std::string folder)
	{
		if (folder.size() > 1 && folder[1] == ':')
		{
			bool has_error = false;
			getFiles(folder.substr(0, 2) + os_file_sep(), &has_error);

			if (has_error)
			{
				return "volume_not_accessible";
			}
		}

		if ((folder.size() > 2 && folder[0] == '\\'
			&& folder[1] == '\\'
			&& folder[2] != '?')
			|| next(folder, 0, "\\\\?\\UNC"))
		{
			bool has_error = false;
			getFiles(folder, &has_error);

			if (has_error && os_last_error() == 5
				|| os_last_error() == 1326)
			{
				return "folder_unc_access_denied";
			}
		}

		return std::string();
	}

	bool is_stop_show(IDatabase* db, std::string stop_key)
	{
		db_results res = db->Read("SELECT tvalue FROM misc WHERE tkey='stop_show'");
		if (!res.empty())
		{
			std::vector<std::string> toks;
			Tokenize(res[0]["tvalue"], toks, ",");
			return std::find(toks.begin(), toks.end(), stop_key) != toks.end();
		}
		return false;
	}

	void add_stop_show(IDatabase* db, JSON::Object& ret, std::string dir_error_stop_show_key)
	{
		ret.set("dir_error_stop_show_key", dir_error_stop_show_key);
		if (is_stop_show(db, dir_error_stop_show_key))
		{
			ret.set("dir_error_show", false);
		}
	}

	void access_dir_checks(IDatabase* db, ServerSettings& settings, std::string backupfolder, std::string backupfolder_uncompr,
		JSON::Object& ret)
	{
#ifdef _WIN32
		if (backupfolder.size() == 2 && backupfolder[1] == ':')
		{
			backupfolder += os_file_sep();
		}
		if (backupfolder_uncompr.size() == 2 && backupfolder_uncompr[1] == ':')
		{
			backupfolder_uncompr += os_file_sep();
		}
#endif

		if (backupfolder.empty() || !os_directory_exists(os_file_prefix(backupfolder)) || !os_directory_exists(os_file_prefix(backupfolder_uncompr)))
		{
			if (!backupfolder.empty())
			{
				ret.set("system_err", os_last_error_str());
			}

			ret.set("dir_error", true);

			if (settings.getSettings()->backupfolder.empty())
			{
				ret.set("dir_error_ext", "err_name_empty");
			}
			else if (!os_directory_exists(os_file_prefix(settings.getSettings()->backupfolder)))
			{
				ret.set("dir_error_ext", "err_folder_not_found");
				add_stop_show(db, ret, "dir_error_not_found");
			}
			else
			{
				add_stop_show(db, ret, "dir_error_misc");
			}

#ifdef _WIN32
			std::string hint = access_dir_hint(settings.getSettings()->backupfolder);
			if (!hint.empty())
			{
				ret.set("dir_error_hint", hint);
			}
#endif

#ifndef _WIN32
			ret.set("detail_err_str", access_err_details(settings.getSettings()->backupfolder));
#endif
		}
		else if (!os_directory_exists(os_file_prefix(backupfolder + os_file_sep() + "clients")) && !os_create_dir(os_file_prefix(backupfolder + os_file_sep() + "clients")))
		{
			ret.set("system_err", os_last_error_str());
			ret.set("dir_error", true);
			ret.set("dir_error_ext", "err_cannot_create_subdir");

			add_stop_show(db, ret, "dir_error_cannot_create_subdir");

#ifdef _WIN32
			std::string hint = access_dir_hint(backupfolder);
			if (!hint.empty())
			{
				ret.set("dir_error_hint", hint);
			}
#endif
		}
		else
		{
			bool has_access_error = false;
			std::string testfoldername = "testfolderHvfgh---dFFoeRRRf";
			std::string testfolderpath = backupfolder + os_file_sep() + testfoldername;
			if (os_directory_exists(os_file_prefix(testfolderpath)))
			{
				if (!os_remove_dir(os_file_prefix(testfolderpath)))
				{
					ret.set("system_err", os_last_error_str());
					ret.set("dir_error", true);
					ret.set("dir_error_ext", "err_cannot_create_subdir");
					add_stop_show(db, ret, "dir_error_cannot_create_subdir2");
					has_access_error = true;
#ifdef _WIN32
					std::string hint = access_dir_hint(backupfolder);
					if (!hint.empty())
					{
						ret.set("dir_error_hint", hint);
					}
#endif
				}
			}

			SSettings* server_settings = settings.getSettings();

			if (!has_access_error
				&& !os_create_dir(os_file_prefix(testfolderpath)))
			{
				ret.set("system_err", os_last_error_str());
				ret.set("dir_error", true);
				ret.set("dir_error_ext", "err_cannot_create_subdir");
				add_stop_show(db, ret, "dir_error_cannot_create_subdir3");

#ifdef _WIN32
				std::string hint = access_dir_hint(backupfolder);
				if (!hint.empty())
				{
					ret.set("dir_error_hint", hint);
				}
#endif
				has_access_error = true;
			}
#ifdef _WIN32
			else if (!server_settings->no_file_backups
				&& os_directory_exists(os_file_prefix(backupfolder + os_file_sep() + "testfo~1")))
			{
				ret.set("dir_error", true);
				ret.set("dir_error_ext", "dos_names_created");
				add_stop_show(db, ret, "dos_names_created");
				ret.set("dir_error_hint", "dos_names_created");
				if (backupfolder.size() > 2
					&& backupfolder[1] == ':')
				{
					ret.set("dir_error_volume", backupfolder.substr(0, 2));
				}
				else
				{
					ret.set("dir_error_volume", "<VOLUME>");
				}
			}
#endif

			if (!server_settings->no_file_backups)
			{
				std::string linkfolderpath = testfolderpath + "_link";
				os_remove_symlink_dir(os_file_prefix(linkfolderpath));
				Server->deleteFile(os_file_prefix(linkfolderpath));

				if (!has_access_error
					&& !os_link_symbolic(os_file_prefix(testfolderpath), os_file_prefix(linkfolderpath)))
				{
					ret.set("system_err", os_last_error_str());
					ret.set("dir_error", true);
					ret.set("dir_error_ext", "err_cannot_create_symbolic_links");
					ret.set("dir_error_hint", "UrBackup cannot create symbolic links on the backup storage. "
						"Your backup storage must support symbolic links in order for UrBackup to work correctly. "
						"The UrBackup Server must run as administrative user on Windows (If not you get error code 1314). "
						"Note: As of 2016-05-07 samba (which is used by many Linux based NAS operating systems for Windows file sharing) has not "
						"implemented the necessary functionality to support symbolic link creation from Windows (With this you get error code 4390).");
					add_stop_show(db, ret, "dir_error_cannot_create_symbolic_links");
				}

				os_remove_symlink_dir(os_file_prefix(linkfolderpath));
			}

			if (!server_settings->no_file_backups)
			{
				bool use_tmpfiles = server_settings->use_tmpfiles;
				std::string tmpfile_path;
				if (!use_tmpfiles)
				{
					tmpfile_path = server_settings->backupfolder + os_file_sep() + "urbackup_tmp_files";
				}

				std::auto_ptr<IFile> tmp_f(ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, logid_t()));

				if (tmp_f.get() == NULL)
				{
					ret.set("tmpdir_error", true);
					ret.set("tmpdir_error_stop_show_key", "tmpdir_error");
					if (is_stop_show(db, "tmpdir_error"))
					{
						ret.set("tmpdir_error_show", false);
					}
				}
				else
				{
					std::string teststring = base64_decode("WDVPIVAlQEFQWzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCo=");
					tmp_f->Write(teststring);
					std::string tmp_fn = tmp_f->getFilename();
					tmp_f.reset();
					tmp_f.reset(Server->openFile(tmp_fn, MODE_RW));

					std::string readstring;
					if (tmp_f.get() != NULL)
					{
						readstring = tmp_f->Read(static_cast<_u32>(teststring.size()));
					}

					tmp_f.reset();
					Server->deleteFile(tmp_fn);

					if (teststring != readstring)
					{
						ret.set("virus_error", true);
						ret.set("virus_error_path", ExtractFilePath(tmp_fn));
						ret.set("virus_error_stop_show_key", "virus_error");
						if (is_stop_show(db, "virus_error"))
						{
							ret.set("virus_error_show", false);
						}
					}
				}
			}

			if (!has_access_error
				&& !os_remove_dir(os_file_prefix(testfolderpath)))
			{
				ret.set("system_err", os_last_error_str());
				ret.set("dir_error", true);
				ret.set("dir_error_ext", "err_cannot_create_subdir");
				add_stop_show(db, ret, "dir_error_cannot_create_subdir4");
				has_access_error = true;
			}
		}

		IFile *tmp = Server->openTemporaryFile();
		ScopedDeleteFile delete_tmp_file(tmp);
		if (tmp == NULL)
		{
			ret.set("tmpdir_error", true);
			ret.set("tmpdir_error_stop_show_key", "tmpdir_error");
			if (is_stop_show(db, "tmpdir_error"))
			{
				ret.set("tmpdir_error_show", false);
			}
		}
	}
}

ACTION_IMPL(status_check)
{
	Helper helper(tid, &POST, &PARAMS);
	JSON::Object ret;

	std::string rights = helper.getRights("status");
	SUser *session = helper.getSession();
	if (session != NULL && session->id == SESSION_ID_INVALID) return;
	if (session != NULL && rights == "all")
	{
		IDatabase *db = helper.getDatabase();
		helper.releaseAll();
		ServerSettings settings(db);
		access_dir_checks(db, settings, settings.getSettings()->backupfolder,
			settings.getSettings()->backupfolder_uncompr, ret);
	}
	else
	{
		ret.set("error", 1);
	}
	helper.Write(ret.stringify(false));
}<|endoftext|>


<commit_before>#include "socket.h"

// PDTK
#include <cxxutils/error_helpers.h>
#include <cxxutils/colors.h>

static_assert(CMSG_SPACE(sizeof(int)) <= 64, "seriously?");

namespace posix
{
  inline bool peercred(fd_t socket, proccred_t& cred) noexcept
    { return ::peercred(socket, cred) == posix::success_response; }
}

GenericSocket::GenericSocket(EDomain   domain,
                             EType     type,
                             EProtocol protocol,
                             int       flags) noexcept
  : GenericSocket(posix::socket(domain, type, protocol, flags)) { }

GenericSocket::GenericSocket(posix::fd_t socket) noexcept
  : m_connected(false), m_socket(socket)
{
  Object::connect(m_socket, EventFlags::Readable, this, &GenericSocket::read); // monitor socket connection
}

GenericSocket::~GenericSocket(void) noexcept { disconnect(); }

void GenericSocket::disconnect(void) noexcept
{
  if(m_selfaddr != EDomain::unspec)
  {
    ::unlink(m_selfaddr.sun_path);
    m_selfaddr = EDomain::unspec;
  }

  if(m_socket != posix::invalid_descriptor)
  {
    Object::enqueue(disconnected, m_socket);
    Object::disconnect(m_socket, EventFlags::Readable);
    posix::close(m_socket); // connection severed!
    m_socket = posix::invalid_descriptor;
  }

  m_connected = false;
}

bool ClientSocket::connect(const char *socket_path) noexcept
{
  flaw(m_connected, posix::warning,,false,
       "Client socket is already connected!")

  flaw(std::strlen(socket_path) >= sizeof(sockaddr_un::sun_path),posix::warning,,false,
       "socket_path exceeds the maximum path length, %lu bytes", sizeof(sockaddr_un::sun_path))

  posix::sockaddr_t peeraddr;
  proccred_t peercred;

  peeraddr = socket_path;
  peeraddr = EDomain::local;
  m_selfaddr = EDomain::unspec;

  flaw(!posix::connect(m_socket, peeraddr, peeraddr.size()), posix::warning,, false,
       "connect() failure: %s", std::strerror(errno)) // connect to peer process
  m_connected = true;

  flaw(!posix::peercred(m_socket, peercred), posix::warning,, false,
       "peercred() failure: %s", std::strerror(errno)) // get creditials of connected peer process

  Object::enqueue(connected, m_socket, peeraddr, peercred);
  return true;
}

bool ClientSocket::write(const vfifo& buffer, posix::fd_t fd) const noexcept
{
  msghdr header = {};
  iovec iov = {};
  char aux_buffer[64] = { 0 };

  header.msg_iov = &iov;
  header.msg_iovlen = 1;
  header.msg_control = aux_buffer;

  iov.iov_base = buffer.begin();
  iov.iov_len = buffer.size();

  header.msg_controllen = 0;

  if(fd != posix::invalid_descriptor) // if a file descriptor needs to be sent
  {
    header.msg_controllen = CMSG_SPACE(sizeof(int));
    cmsghdr* cmsg = CMSG_FIRSTHDR(&header);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = fd;
  }

  flaw(posix::sendmsg(m_socket, &header) == posix::error_response, posix::warning,,false,
       "sendmsg() failure: %s", std::strerror(errno))
  return true;
}

bool ClientSocket::read(posix::fd_t socket, EventData_t event) noexcept
{
  (void)event;
  flaw(m_socket != socket, posix::critical, std::exit(2), false,
       "An 'impossible' situation has occurred.")

  msghdr header = {};
  iovec iov = {};
  char aux_buffer[64] = { 0 };

  header.msg_iov = &iov;
  header.msg_iovlen = 1;
  header.msg_control = aux_buffer;

  iov.iov_base = m_buffer.begin();
  iov.iov_len = m_buffer.capacity();
  header.msg_controllen = CMSG_SPACE(sizeof(int));

  posix::ssize_t byte_count = posix::recvmsg(m_socket, &header, 0);

  flaw(byte_count == posix::error_response, posix::warning,, false,
       "recvmsg() failure: %s", std::strerror(errno))

  flaw(!byte_count, posix::information, disconnect(), false,
       "Socket disconnected.")

  flaw(!m_buffer.resize(byte_count), posix::severe, posix::error(std::errc::not_enough_memory), false,
       "Failed to resize buffer to %li bytes", byte_count)

  posix::fd_t fd = posix::invalid_descriptor;
  if(header.msg_controllen == CMSG_SPACE(sizeof(int)))
  {
    cmsghdr* cmsg = CMSG_FIRSTHDR(&header);
    if(cmsg->cmsg_level == SOL_SOCKET &&
       cmsg->cmsg_type == SCM_RIGHTS &&
       cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
      fd = *reinterpret_cast<int*>(CMSG_DATA(cmsg));
  }
  else
  { flaw(header.msg_flags, posix::warning,, false,
         "error, message flags: 0x%04x", header.msg_flags) }

  Object::enqueue(newMessage, m_socket, m_buffer, fd);
  return true;
}

bool ServerSocket::bind(const char* socket_path, EDomain domain, int socket_backlog) noexcept
{
  flaw(m_connected, posix::warning,,false,
       "Server socket is already bound!")

  flaw(socket_path == nullptr,posix::warning,,false,
       "socket_path is a null value")

  flaw(std::strlen(socket_path) >= sizeof(sockaddr_un::sun_path),posix::warning,,false,
       "socket_path exceeds the maximum path length, %lu bytes", sizeof(sockaddr_un::sun_path))

  m_selfaddr = socket_path;
  m_selfaddr = domain;

  flaw(!posix::bind(m_socket, m_selfaddr, m_selfaddr.size()),posix::warning,,false,
       "Unable to bind to socket to %s: %s", socket_path, std::strerror(errno))
  m_connected = true;

  flaw(!posix::listen(m_socket, socket_backlog),posix::warning,,false,
       "Unable to listen to server socket: %s", std::strerror(errno))
  return true;
}

bool ServerSocket::peerData(posix::fd_t socket, posix::sockaddr_t* addr, proccred_t* creds) const noexcept
{
  auto peer = m_peers.find(socket);
  if(peer == m_peers.end())
    return false;

  if(addr != nullptr)
    *addr = peer->second.addr;
  if(creds != nullptr)
    *creds = peer->second.creds;
  return true;
}

void ServerSocket::acceptPeerRequest(posix::fd_t socket) noexcept
{
  if(m_peers.find(socket) != m_peers.end())
  {
    auto connection = m_connections.emplace(socket, socket).first;
    Object::connect(connection->second.disconnected, this, &ServerSocket::disconnectPeer);
    Object::connect(connection->second.newMessage, newPeerMessage);
    Object::enqueue(connectedPeer, socket);
  }
}

void ServerSocket::rejectPeerRequest(posix::fd_t socket) noexcept
{
  auto peer = m_peers.find(socket);
  if(peer != m_peers.end())
  {
    m_peers.erase(peer);
    posix::close(socket);
  }
}

void ServerSocket::disconnectPeer(posix::fd_t socket) noexcept
{
  m_peers.erase(socket);
  m_connections.erase(socket);
  Object::enqueue(disconnectedPeer, socket);
}

// accepts socket connections and then enqueues newPeerRequest
bool ServerSocket::read(posix::fd_t socket, EventData_t event) noexcept
{
  (void)event;
  flaw(m_socket != socket, posix::critical, std::exit(2), false,
       "An 'impossible' situation has occurred.")
  proccred_t peercred;
  posix::sockaddr_t peeraddr;
  socklen_t addrlen = 0;
  posix::fd_t fd = posix::accept(m_socket, peeraddr, &addrlen); // accept a new socket connection

  flaw(fd == posix::error_response, posix::warning,, false,
       "accept() failure: %s", std::strerror(errno))

  flaw(addrlen >= sizeof(sockaddr_un::sun_path), posix::severe,, false,
       "accept() implementation bug: %s", "address length exceeds availible storage");

  flaw(addrlen != peeraddr.size(), posix::warning,, false,
       "accept() implementation bug: %s", "address length does not match string length");

  flaw(!posix::peercred(fd, peercred), posix::warning,, false,
       "peercred() failure: %s", std::strerror(errno)) // get creditials of connected peer process

  m_peers.emplace(fd, peer_t(fd, peeraddr, peercred));
  Object::enqueue(newPeerRequest, fd, peeraddr, peercred);
  return true;
}

bool ServerSocket::write(posix::fd_t socket, const vfifo& buffer, posix::fd_t fd) const noexcept
{
  auto connection = m_connections.find(socket);
  if(connection != m_connections.end())
    return connection->second.write(buffer, fd);
  return false;
}

<commit_msg>more silly needs for Apple<commit_after>#include "socket.h"

// PDTK
#include <cxxutils/error_helpers.h>
#include <cxxutils/colors.h>

#ifdef __APPLE__
#define AUX_BUFFER_SIZE  256
#else
#define AUX_BUFFER_SIZE  CMSG_SPACE(sizeof(int))
#endif

namespace posix
{
  inline bool peercred(fd_t socket, proccred_t& cred) noexcept
    { return ::peercred(socket, cred) == posix::success_response; }
}

GenericSocket::GenericSocket(EDomain   domain,
                             EType     type,
                             EProtocol protocol,
                             int       flags) noexcept
  : GenericSocket(posix::socket(domain, type, protocol, flags)) { }

GenericSocket::GenericSocket(posix::fd_t socket) noexcept
  : m_connected(false), m_socket(socket)
{
  Object::connect(m_socket, EventFlags::Readable, this, &GenericSocket::read); // monitor socket connection
}

GenericSocket::~GenericSocket(void) noexcept { disconnect(); }

void GenericSocket::disconnect(void) noexcept
{
  if(m_selfaddr != EDomain::unspec)
  {
    ::unlink(m_selfaddr.sun_path);
    m_selfaddr = EDomain::unspec;
  }

  if(m_socket != posix::invalid_descriptor)
  {
    Object::enqueue(disconnected, m_socket);
    Object::disconnect(m_socket, EventFlags::Readable);
    posix::close(m_socket); // connection severed!
    m_socket = posix::invalid_descriptor;
  }

  m_connected = false;
}

bool ClientSocket::connect(const char *socket_path) noexcept
{
  flaw(m_connected, posix::warning,,false,
       "Client socket is already connected!")

  flaw(std::strlen(socket_path) >= sizeof(sockaddr_un::sun_path),posix::warning,,false,
       "socket_path exceeds the maximum path length, %lu bytes", sizeof(sockaddr_un::sun_path))

  posix::sockaddr_t peeraddr;
  proccred_t peercred;

  peeraddr = socket_path;
  peeraddr = EDomain::local;
  m_selfaddr = EDomain::unspec;

  flaw(!posix::connect(m_socket, peeraddr, peeraddr.size()), posix::warning,, false,
       "connect() failure: %s", std::strerror(errno)) // connect to peer process
  m_connected = true;

  flaw(!posix::peercred(m_socket, peercred), posix::warning,, false,
       "peercred() failure: %s", std::strerror(errno)) // get creditials of connected peer process

  Object::enqueue(connected, m_socket, peeraddr, peercred);
  return true;
}

bool ClientSocket::write(const vfifo& buffer, posix::fd_t fd) const noexcept
{
  msghdr header = {};
  iovec iov = {};
  char aux_buffer[AUX_BUFFER_SIZE] = { 0 };

  header.msg_iov = &iov;
  header.msg_iovlen = 1;
  header.msg_control = aux_buffer;

  iov.iov_base = buffer.begin();
  iov.iov_len = buffer.size();

  header.msg_controllen = 0;

  if(fd != posix::invalid_descriptor) // if a file descriptor needs to be sent
  {
    header.msg_controllen = CMSG_SPACE(sizeof(int));
    cmsghdr* cmsg = CMSG_FIRSTHDR(&header);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = fd;
  }

  flaw(posix::sendmsg(m_socket, &header) == posix::error_response, posix::warning,,false,
       "sendmsg() failure: %s", std::strerror(errno))
  return true;
}

bool ClientSocket::read(posix::fd_t socket, EventData_t event) noexcept
{
  (void)event;
  flaw(m_socket != socket, posix::critical, std::exit(2), false,
       "An 'impossible' situation has occurred.")

  msghdr header = {};
  iovec iov = {};
  char aux_buffer[AUX_BUFFER_SIZE] = { 0 };

  header.msg_iov = &iov;
  header.msg_iovlen = 1;
  header.msg_control = aux_buffer;

  iov.iov_base = m_buffer.begin();
  iov.iov_len = m_buffer.capacity();
  header.msg_controllen = CMSG_SPACE(sizeof(int));

  posix::ssize_t byte_count = posix::recvmsg(m_socket, &header, 0);

  flaw(byte_count == posix::error_response, posix::warning,, false,
       "recvmsg() failure: %s", std::strerror(errno))

  flaw(!byte_count, posix::information, disconnect(), false,
       "Socket disconnected.")

  flaw(!m_buffer.resize(byte_count), posix::severe, posix::error(std::errc::not_enough_memory), false,
       "Failed to resize buffer to %li bytes", byte_count)

  posix::fd_t fd = posix::invalid_descriptor;
  if(header.msg_controllen == CMSG_SPACE(sizeof(int)))
  {
    cmsghdr* cmsg = CMSG_FIRSTHDR(&header);
    if(cmsg->cmsg_level == SOL_SOCKET &&
       cmsg->cmsg_type == SCM_RIGHTS &&
       cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
      fd = *reinterpret_cast<int*>(CMSG_DATA(cmsg));
  }
  else
  { flaw(header.msg_flags, posix::warning,, false,
         "error, message flags: 0x%04x", header.msg_flags) }

  Object::enqueue(newMessage, m_socket, m_buffer, fd);
  return true;
}

bool ServerSocket::bind(const char* socket_path, EDomain domain, int socket_backlog) noexcept
{
  flaw(m_connected, posix::warning,,false,
       "Server socket is already bound!")

  flaw(socket_path == nullptr,posix::warning,,false,
       "socket_path is a null value")

  flaw(std::strlen(socket_path) >= sizeof(sockaddr_un::sun_path),posix::warning,,false,
       "socket_path exceeds the maximum path length, %lu bytes", sizeof(sockaddr_un::sun_path))

  m_selfaddr = socket_path;
  m_selfaddr = domain;

  flaw(!posix::bind(m_socket, m_selfaddr, m_selfaddr.size()),posix::warning,,false,
       "Unable to bind to socket to %s: %s", socket_path, std::strerror(errno))
  m_connected = true;

  flaw(!posix::listen(m_socket, socket_backlog),posix::warning,,false,
       "Unable to listen to server socket: %s", std::strerror(errno))
  return true;
}

bool ServerSocket::peerData(posix::fd_t socket, posix::sockaddr_t* addr, proccred_t* creds) const noexcept
{
  auto peer = m_peers.find(socket);
  if(peer == m_peers.end())
    return false;

  if(addr != nullptr)
    *addr = peer->second.addr;
  if(creds != nullptr)
    *creds = peer->second.creds;
  return true;
}

void ServerSocket::acceptPeerRequest(posix::fd_t socket) noexcept
{
  if(m_peers.find(socket) != m_peers.end())
  {
    auto connection = m_connections.emplace(socket, socket).first;
    Object::connect(connection->second.disconnected, this, &ServerSocket::disconnectPeer);
    Object::connect(connection->second.newMessage, newPeerMessage);
    Object::enqueue(connectedPeer, socket);
  }
}

void ServerSocket::rejectPeerRequest(posix::fd_t socket) noexcept
{
  auto peer = m_peers.find(socket);
  if(peer != m_peers.end())
  {
    m_peers.erase(peer);
    posix::close(socket);
  }
}

void ServerSocket::disconnectPeer(posix::fd_t socket) noexcept
{
  m_peers.erase(socket);
  m_connections.erase(socket);
  Object::enqueue(disconnectedPeer, socket);
}

// accepts socket connections and then enqueues newPeerRequest
bool ServerSocket::read(posix::fd_t socket, EventData_t event) noexcept
{
  (void)event;
  flaw(m_socket != socket, posix::critical, std::exit(2), false,
       "An 'impossible' situation has occurred.")
  proccred_t peercred;
  posix::sockaddr_t peeraddr;
  socklen_t addrlen = 0;
  posix::fd_t fd = posix::accept(m_socket, peeraddr, &addrlen); // accept a new socket connection

  flaw(fd == posix::error_response, posix::warning,, false,
       "accept() failure: %s", std::strerror(errno))

  flaw(addrlen >= sizeof(sockaddr_un::sun_path), posix::severe,, false,
       "accept() implementation bug: %s", "address length exceeds availible storage");

  flaw(addrlen != peeraddr.size(), posix::warning,, false,
       "accept() implementation bug: %s", "address length does not match string length");

  flaw(!posix::peercred(fd, peercred), posix::warning,, false,
       "peercred() failure: %s", std::strerror(errno)) // get creditials of connected peer process

  m_peers.emplace(fd, peer_t(fd, peeraddr, peercred));
  Object::enqueue(newPeerRequest, fd, peeraddr, peercred);
  return true;
}

bool ServerSocket::write(posix::fd_t socket, const vfifo& buffer, posix::fd_t fd) const noexcept
{
  auto connection = m_connections.find(socket);
  if(connection != m_connections.end())
    return connection->second.write(buffer, fd);
  return false;
}

<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_HH
#define DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_HH

#include <memory>

#include <dune/stuff/grid/partview.hh>
#include <dune/stuff/grid/provider/interface.hh>

#include "interface.hh"
#include "continuouslagrange/fem-localfunctions.hh"
#include "continuouslagrange/fem.hh"
#include "continuouslagrange/pdelab.hh"

namespace Dune {
namespace GDT {
namespace Spaces {

template <class GridType, Stuff::Grid::ChooseLayer layer_type, ChooseSpaceBackend backend_type, int polOrder,
          class RangeFieldType, int dimRange, int dimRangeCols = 1>
class ContinuousLagrangeSpace
{
  static const Stuff::Grid::ChoosePartView part_view_type = ChooseGridPartView<backend_type>::type;

public:
  typedef typename Stuff::Grid::Layer<GridType, layer_type, part_view_type>::Type GridLayerType;

private:
  template <class G, int p, class R, int r, int rC, GDT::ChooseSpaceBackend b>
  struct SpaceChooser
  {
    static_assert(AlwaysFalse<G>::value, "No space available for this backend!");
  };

  template <class G, int p, class R, int r, int rC>
  struct SpaceChooser<G, p, R, r, rC, GDT::ChooseSpaceBackend::fem>
  {
    typedef GDT::Spaces::ContinuousLagrange::FemBased<GridLayerType, p, R, r> Type;
  };

  template <class G, int p, class R, int r, int rC>
  struct SpaceChooser<G, p, R, r, rC, GDT::ChooseSpaceBackend::fem_localfunction>
  {
    typedef GDT::Spaces::ContinuousLagrange::FemLocalfunctionsBased<GridLayerType, p, R, r> Type;
  };

  template <class G, int p, class R, int r, int rC>
  struct SpaceChooser<G, p, R, r, rC, GDT::ChooseSpaceBackend::pdelab>
  {
    typedef GDT::Spaces::ContinuousLagrange::PdelabBased<GridLayerType, p, R, r> Type;
  };

public:
  typedef typename SpaceChooser<GridType, polOrder, RangeFieldType, dimRange, dimRangeCols, backend_type>::Type Type;

  static Type create(const std::shared_ptr<const GridLayerType> grid_layer)
  {
    return Type(grid_layer);
  }

  static Type create(const Stuff::Grid::ConstProviderInterface<GridType>& grid_provider, const int level = 0)
  {
    return Type(grid_provider.template layer<layer_type, part_view_type>(level));
  }
}; // class ContinuousLagrangeSpace

} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_HH
<commit_msg>[space.cg] rename ContinuousLagrange{Space,Provider}<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_HH
#define DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_HH

#include <memory>

#include <dune/stuff/grid/partview.hh>
#include <dune/stuff/grid/provider/interface.hh>

#include "interface.hh"
#include "continuouslagrange/fem-localfunctions.hh"
#include "continuouslagrange/fem.hh"
#include "continuouslagrange/pdelab.hh"

namespace Dune {
namespace GDT {
namespace Spaces {

template <class GridType, Stuff::Grid::ChooseLayer layer_type, ChooseSpaceBackend backend_type, int polOrder,
          class RangeFieldType, int dimRange, int dimRangeCols = 1>
class ContinuousLagrangeProvider
{
  static const Stuff::Grid::ChoosePartView part_view_type = ChooseGridPartView<backend_type>::type;

public:
  typedef typename Stuff::Grid::Layer<GridType, layer_type, part_view_type>::Type GridLayerType;

private:
  template <class G, int p, class R, int r, int rC, GDT::ChooseSpaceBackend b>
  struct SpaceChooser
  {
    static_assert(AlwaysFalse<G>::value, "No space available for this backend!");
  };

  template <class G, int p, class R, int r, int rC>
  struct SpaceChooser<G, p, R, r, rC, GDT::ChooseSpaceBackend::fem>
  {
    typedef GDT::Spaces::ContinuousLagrange::FemBased<GridLayerType, p, R, r> Type;
  };

  template <class G, int p, class R, int r, int rC>
  struct SpaceChooser<G, p, R, r, rC, GDT::ChooseSpaceBackend::fem_localfunction>
  {
    typedef GDT::Spaces::ContinuousLagrange::FemLocalfunctionsBased<GridLayerType, p, R, r> Type;
  };

  template <class G, int p, class R, int r, int rC>
  struct SpaceChooser<G, p, R, r, rC, GDT::ChooseSpaceBackend::pdelab>
  {
    typedef GDT::Spaces::ContinuousLagrange::PdelabBased<GridLayerType, p, R, r> Type;
  };

public:
  typedef typename SpaceChooser<GridType, polOrder, RangeFieldType, dimRange, dimRangeCols, backend_type>::Type Type;

  static Type create(const std::shared_ptr<const GridLayerType> grid_layer)
  {
    return Type(grid_layer);
  }

  static Type create(const Stuff::Grid::ConstProviderInterface<GridType>& grid_provider, const int level = 0)
  {
    return Type(grid_provider.template layer<layer_type, part_view_type>(level));
  }
}; // class ContinuousLagrangeProvider

} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_HH
<|endoftext|>


<commit_before>/// \file DefaultModuleCache.cpp

#include "chi/DefaultModuleCache.hpp"
#include "chi/Context.hpp"
#include "chi/LLVMVersion.hpp"
#include "chi/ModuleCache.hpp"
#include "chi/BitcodeParser.hpp"
#include "chi/Support/Result.hpp"

#include <cassert>

#include <boost/filesystem/operations.hpp>

#if LLVM_VERSION_LESS_EQUAL(3, 9)
#include <llvm/Bitcode/ReaderWriter.h>
#else
#include <llvm/Bitcode/BitcodeWriter.h>
#endif

#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_ostream.h>

namespace chi {

DefaultModuleCache::DefaultModuleCache(chi::Context& ctx) : ModuleCache{ctx} {}

Result DefaultModuleCache::cacheModule(const boost::filesystem::path& moduleName,
                                       llvm::Module& compiledModule, std::time_t timeAtFileRead) {
	assert(!moduleName.empty() &&
	       "Cannot pass a empty module name to DefaultModuleCache::cacheModule");

	Result res;

	auto cachePath = cachePathForModule(moduleName);

	// make the directories
	boost::filesystem::create_directories(cachePath.parent_path());

	// open & write
	{
		// open the file
		std::error_code      errCode;
		llvm::raw_fd_ostream fileStream(cachePath.string(), errCode, llvm::sys::fs::F_RW);

		if (errCode) {
			res.addEntry("EUKN", "Failed to open file", {{"Path", cachePath.string()}});
			return res;
		}

		// write it
		llvm::WriteBitcodeToFile(&compiledModule, fileStream);
	}

	// set age to be correct
	boost::filesystem::last_write_time(cachePath, timeAtFileRead);

	return res;
}

boost::filesystem::path DefaultModuleCache::cachePathForModule(
    const boost::filesystem::path& moduleName) const {
	return context().workspacePath() / "lib" / (moduleName.string() + ".bc");
}

void DefaultModuleCache::invalidateCache(const boost::filesystem::path& moduleName) {
	assert(!moduleName.empty() && "Cannot pass empty path to DefaultModuleCache::invalidateCache");

	auto cachePath = cachePathForModule(moduleName);

	boost::filesystem::remove(cachePath);
}

std::time_t DefaultModuleCache::cacheUpdateTime(const boost::filesystem::path& moduleName) const {
	return boost::filesystem::last_write_time(cachePathForModule(moduleName));
}

std::unique_ptr<llvm::Module> DefaultModuleCache::retrieveFromCache(
    const boost::filesystem::path& moduleName, std::time_t atLeastThisNew) {
	assert(!moduleName.empty() &&
	       "Cannot pass empty path to DefaultModuleCache::retrieveFromCache");

	auto cachePath = cachePathForModule(moduleName);

	// if there is no cache, then there is nothing to retrieve
	if (!boost::filesystem::is_regular_file(cachePath)) { return nullptr; }

	// see if the cache is new enough
	auto cacheEditTime = cacheUpdateTime(moduleName);
	if (cacheEditTime < atLeastThisNew) { return nullptr; }

	// read the cache
	std::unique_ptr<llvm::Module> fetchedMod;
	auto res = parseBitcodeFile(cachePath, context().llvmContext(), &fetchedMod);

	if (!res) { return nullptr; }

	return fetchedMod;
}

}  // namespace chi
<commit_msg>Add file stream compat<commit_after>/// \file DefaultModuleCache.cpp

#include "chi/DefaultModuleCache.hpp"
#include "chi/Context.hpp"
#include "chi/LLVMVersion.hpp"
#include "chi/ModuleCache.hpp"
#include "chi/BitcodeParser.hpp"
#include "chi/Support/Result.hpp"

#include <cassert>

#include <boost/filesystem/operations.hpp>

#if LLVM_VERSION_LESS_EQUAL(3, 9)
#include <llvm/Bitcode/ReaderWriter.h>
#else
#include <llvm/Bitcode/BitcodeWriter.h>
#endif

#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_ostream.h>

namespace chi {

DefaultModuleCache::DefaultModuleCache(chi::Context& ctx) : ModuleCache{ctx} {}

Result DefaultModuleCache::cacheModule(const boost::filesystem::path& moduleName,
                                       llvm::Module& compiledModule, std::time_t timeAtFileRead) {
	assert(!moduleName.empty() &&
	       "Cannot pass a empty module name to DefaultModuleCache::cacheModule");

	Result res;

	auto cachePath = cachePathForModule(moduleName);

	// make the directories
	boost::filesystem::create_directories(cachePath.parent_path());

	// open & write
	{
		// open the file
		std::error_code      errCode;
        std::string errString;
        llvm::raw_fd_ostream fileStream {
			cachePath.string(),
#if LLVM_VERSION_LESS_EQUAL(3, 5)
			    errorString,
#else
			    errCode,
#endif
			    llvm::sys::fs::F_RW
		};

		if (errCode || !errString.empty()) {
			res.addEntry("EUKN", "Failed to open file", {{"Path", cachePath.string()}});
			return res;
		}

		// write it
		llvm::WriteBitcodeToFile(&compiledModule, fileStream);
	}

	// set age to be correct
	boost::filesystem::last_write_time(cachePath, timeAtFileRead);

	return res;
}

boost::filesystem::path DefaultModuleCache::cachePathForModule(
    const boost::filesystem::path& moduleName) const {
	return context().workspacePath() / "lib" / (moduleName.string() + ".bc");
}

void DefaultModuleCache::invalidateCache(const boost::filesystem::path& moduleName) {
	assert(!moduleName.empty() && "Cannot pass empty path to DefaultModuleCache::invalidateCache");

	auto cachePath = cachePathForModule(moduleName);

	boost::filesystem::remove(cachePath);
}

std::time_t DefaultModuleCache::cacheUpdateTime(const boost::filesystem::path& moduleName) const {
	return boost::filesystem::last_write_time(cachePathForModule(moduleName));
}

std::unique_ptr<llvm::Module> DefaultModuleCache::retrieveFromCache(
    const boost::filesystem::path& moduleName, std::time_t atLeastThisNew) {
	assert(!moduleName.empty() &&
	       "Cannot pass empty path to DefaultModuleCache::retrieveFromCache");

	auto cachePath = cachePathForModule(moduleName);

	// if there is no cache, then there is nothing to retrieve
	if (!boost::filesystem::is_regular_file(cachePath)) { return nullptr; }

	// see if the cache is new enough
	auto cacheEditTime = cacheUpdateTime(moduleName);
	if (cacheEditTime < atLeastThisNew) { return nullptr; }

	// read the cache
	std::unique_ptr<llvm::Module> fetchedMod;
	auto res = parseBitcodeFile(cachePath, context().llvmContext(), &fetchedMod);

	if (!res) { return nullptr; }

	return fetchedMod;
}

}  // namespace chi
<|endoftext|>