<commit_before>/*
*
* Copyright 2014 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <string.h>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/globals.h"
#include "parse/forbiddenChars.h"

/* ****************************************************************************
*
* commonForbidden
*/
inline static bool commonForbidden(char c)
{
  switch (c)
  {
  case '<':
  case '>':
  case '"':
  case '\'':
  case '=':
  case ';':
  case '(':
  case ')':
    return true;
  }
  return false;
}

/* ****************************************************************************
*
* forbiddenChars -
*/
bool forbiddenChars(const char* s, const char* exceptions)
{
  if (s == (void*) 0)
  {
    return false;
  }

  while (*s != 0)
  {
    if ((exceptions != NULL) && (strchr(exceptions, *s) != NULL))
    {
      ++s;
      continue;
    }

    if (commonForbidden(*s))
    {
      return true;
    }

    ++s;
  }

  return false;
}

/* ****************************************************************************
*
* forbiddenIdChars -
*/
bool forbiddenIdChars(int api, const char* s, const char* exceptions)
{
  if (api == 1 && !checkIdv1)
  {
    return forbiddenChars(s, exceptions);  // old behavior
  }

  return forbiddenIdCharsV2(s, exceptions);
}

/* ****************************************************************************
*
* forbiddenIdCharsV2 -
*/
bool forbiddenIdCharsV2(const char* s, const char* exceptions)
{
  if (s == (void*) 0)
  {
    return false;
  }

  while (*s != 0)
  {
    if ((exceptions != NULL) && (strchr(exceptions, *s) != NULL))
    {
      ++s;
      continue;
    }

    if (*s >= 127 || *s <= 32)
    {
      return true;
    }

    switch (*s)
    {
    case '?':
    case '/':
    case '#':
    case '&':
      return true;
    }

    // Plus common set of forbidden chars
    if(commonForbidden(*s))
    {
      return true;
    }

    ++s;
  }

  return false;
}

/* ****************************************************************************
*
* forbiddenQuotes - any unauthorized quotes?
*
* Quotes are used to delimit attribute/metadata/compound-node names that contain a dot.
*
* Example:
*   We have an attribute A with a metadata called 'M.x'.
*   To do a string filter (mq) on M.x, we need to use quotes.
*   A.M.x is interpreted as attribute A, metadata M, compound node x
*   A.'M.x' is what we need to reach the metadata M.x.
*
* So, quotes are allowed as first and last character, and if there is a dot
* before or after the quote.
*
* If a dot is found elsewhere, an error should be returned.
*/
bool forbiddenQuotes(char* s)
{
  int ix = 0;

  while (s[ix] != 0)
  {
    ++ix;  // Remember, quote is allowed as first char, ok to step over ix==0

    if (s[ix] == '\'')
    {
      if      (s[ix - 1] == '.')  {}  // OK - a.'x.b' is allowed (see quote in pos 2 - dot before)
      else if (s[ix + 1] == '.')  {}  // OK - a.'x.b'.c is allowed (see quote in pos 6 - dot after)
      else if (s[ix + 1] == 0)    {}  // OK - quote as last char is allowed
      else
      {
        return true;  // NOT OK - unauthorized quote found
      }
    }
  }

  return false;
}
<commit_msg>improved explanation of forbiddenQuotes<commit_after>/*
*
* Copyright 2014 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <string.h>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/globals.h"
#include "parse/forbiddenChars.h"

/* ****************************************************************************
*
* commonForbidden
*/
inline static bool commonForbidden(char c)
{
  switch (c)
  {
  case '<':
  case '>':
  case '"':
  case '\'':
  case '=':
  case ';':
  case '(':
  case ')':
    return true;
  }
  return false;
}

/* ****************************************************************************
*
* forbiddenChars -
*/
bool forbiddenChars(const char* s, const char* exceptions)
{
  if (s == (void*) 0)
  {
    return false;
  }

  while (*s != 0)
  {
    if ((exceptions != NULL) && (strchr(exceptions, *s) != NULL))
    {
      ++s;
      continue;
    }

    if (commonForbidden(*s))
    {
      return true;
    }

    ++s;
  }

  return false;
}

/* ****************************************************************************
*
* forbiddenIdChars -
*/
bool forbiddenIdChars(int api, const char* s, const char* exceptions)
{
  if (api == 1 && !checkIdv1)
  {
    return forbiddenChars(s, exceptions);  // old behavior
  }

  return forbiddenIdCharsV2(s, exceptions);
}

/* ****************************************************************************
*
* forbiddenIdCharsV2 -
*/
bool forbiddenIdCharsV2(const char* s, const char* exceptions)
{
  if (s == (void*) 0)
  {
    return false;
  }

  while (*s != 0)
  {
    if ((exceptions != NULL) && (strchr(exceptions, *s) != NULL))
    {
      ++s;
      continue;
    }

    if (*s >= 127 || *s <= 32)
    {
      return true;
    }

    switch (*s)
    {
    case '?':
    case '/':
    case '#':
    case '&':
      return true;
    }

    // Plus common set of forbidden chars
    if(commonForbidden(*s))
    {
      return true;
    }

    ++s;
  }

  return false;
}

/* ****************************************************************************
*
* forbiddenQuotes - any unauthorized quotes?
*
* Quotes (') are used to delimit attribute/metadata/compound-node names that contain a dot (.).
*
* Example (of metadata, but valid also for attribute name and compound node name):
*   We have an attribute A with a metadata called "M.x" (without double-quotes - 3 chars).
*   For a string filter (mq) on M.x, we need to use quotes.
*   A.M.x is interpreted as attribute A, metadata M, compound node x
*   A.'M.x' is what we need to reach the metadata M.x.
*
* So, quotes are allowed as first and last character, and if there is a dot
* before or after the quote.
*
* If a quote is found elsewhere, an error should be returned.
*/
bool forbiddenQuotes(char* s)
{
  int ix = 0;

  while (s[ix] != 0)
  {
    ++ix;  // Remember, quote is allowed as first char, ok to step over ix==0

    if (s[ix] == '\'')
    {
      if      (s[ix - 1] == '.')  {}  // OK - a.'x.b' is allowed (see quote in pos 2 - dot before)
      else if (s[ix + 1] == '.')  {}  // OK - a.'x.b'.c is allowed (see quote in pos 6 - dot after)
      else if (s[ix + 1] == 0)    {}  // OK - quote as last char is allowed
      else
      {
        return true;  // NOT OK - unauthorized quote found
      }
    }
  }

  return false;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of Rasterbar Software nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef LIBTORRENT_BUFFER_HPP
#define LIBTORRENT_BUFFER_HPP

#include <memory>
#include <cstring>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent {

class buffer
{
public:
	struct interval
	{
	   interval()
		  : begin(0)
		  , end(0)
		{}

	   interval(char* begin, char* end)
		  : begin(begin)
		  , end(end)
		{}

		char operator[](int index) const
		{
			TORRENT_ASSERT(begin + index < end);
			return begin[index];
		}

		int left() const { TORRENT_ASSERT(end >= begin); return end - begin; }

		char* begin;
		char* end;
	};

	struct const_interval
	{
	   const_interval(interval const& i)
		  : begin(i.begin)
		  , end(i.end)
		{}

	   const_interval(char const* begin, char const* end)
		  : begin(begin)
		  , end(end)
		{}

		char operator[](int index) const
		{
			TORRENT_ASSERT(begin + index < end);
			return begin[index];
		}

		bool operator==(const const_interval& p_interval)
		{
			return (begin == p_interval.begin
				&& end == p_interval.end);
		}

		int left() const { TORRENT_ASSERT(end >= begin); return end - begin; }

		char const* begin;
		char const* end;
	};

	buffer(std::size_t n = 0)
		: m_begin(0)
		, m_end(0)
		, m_last(0)
	{
		if (n) resize(n);
	}

	buffer(buffer const& b)
		: m_begin(0)
		, m_end(0)
		, m_last(0)
	{
		if (b.size() == 0) return;
		resize(b.size());
		std::memcpy(m_begin, b.begin(), b.size());
	}

	buffer& operator=(buffer const& b)
	{
		resize(b.size());
		std::memcpy(m_begin, b.begin(), b.size());
		return *this;
	}

	~buffer()
	{
		::operator delete (m_begin);
	}

	buffer::interval data() { return interval(m_begin, m_end); }
	buffer::const_interval data() const { return const_interval(m_begin, m_end); }

	void resize(std::size_t n)
	{
		reserve(n);
		m_end = m_begin + n;
	}

	void insert(char* point, char const* first, char const* last)
	{
		std::size_t p = point - m_begin;
		if (point == m_end)
		{
			resize(size() + last - first);
			std::memcpy(m_begin + p, first, last - first);
			return;
		}

		resize(size() + last - first);
		std::memmove(m_begin + p + (last - first), m_begin + p, last - first);
		std::memcpy(m_begin + p, first, last - first);
	}

	void erase(char* begin, char* end)
	{
		TORRENT_ASSERT(end <= m_end);
		TORRENT_ASSERT(begin >= m_begin);
		TORRENT_ASSERT(begin <= end);
	 	if (end == m_end)
		{
			resize(begin - m_begin);
			return;
		}
		std::memmove(begin, end, m_end - end);
		m_end = begin + (m_end - end);
	 }

	void clear() { m_end = m_begin; }
	std::size_t size() const { return m_end - m_begin; }
	std::size_t capacity() const { return m_last - m_begin; }
	void reserve(std::size_t n)
	{
		if (n <= capacity()) return;
		TORRENT_ASSERT(n > 0);

		char* buf = (char*)::operator new(n);
		std::size_t s = size();
		std::memcpy(buf, m_begin, s);
		::operator delete (m_begin);
		m_begin = buf;
		m_end = buf + s;
		m_last = m_begin + n;
	}

	bool empty() const { return m_begin == m_end; }
	char& operator[](std::size_t i) { TORRENT_ASSERT(i < size()); return m_begin[i]; }
	char const& operator[](std::size_t i) const { TORRENT_ASSERT(i < size()); return m_begin[i]; }

	char* begin() { return m_begin; }
	char const* begin() const { return m_begin; }
	char* end() { return m_end; }
	char const* end() const { return m_end; }

	void swap(buffer& b)
	{
		using std::swap;
		swap(m_begin, b.m_begin);
		swap(m_end, b.m_end);
		swap(m_last, b.m_last);
	}
private:
	char* m_begin; // first
	char* m_end; // one passed end of size
	char* m_last; // one passed end of allocation
};

}

#endif // LIBTORRENT_BUFFER_HPP

<commit_msg>switched over buffer to use realloc/free<commit_after>/*
Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of Rasterbar Software nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef LIBTORRENT_BUFFER_HPP
#define LIBTORRENT_BUFFER_HPP

#include <memory>
#include <cstring>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent {

class buffer
{
public:
	struct interval
	{
	   interval()
		  : begin(0)
		  , end(0)
		{}

	   interval(char* begin, char* end)
		  : begin(begin)
		  , end(end)
		{}

		char operator[](int index) const
		{
			TORRENT_ASSERT(begin + index < end);
			return begin[index];
		}

		int left() const { TORRENT_ASSERT(end >= begin); return end - begin; }

		char* begin;
		char* end;
	};

	struct const_interval
	{
	   const_interval(interval const& i)
		  : begin(i.begin)
		  , end(i.end)
		{}

	   const_interval(char const* begin, char const* end)
		  : begin(begin)
		  , end(end)
		{}

		char operator[](int index) const
		{
			TORRENT_ASSERT(begin + index < end);
			return begin[index];
		}

		bool operator==(const const_interval& p_interval)
		{
			return (begin == p_interval.begin
				&& end == p_interval.end);
		}

		int left() const { TORRENT_ASSERT(end >= begin); return end - begin; }

		char const* begin;
		char const* end;
	};

	buffer(std::size_t n = 0)
		: m_begin(0)
		, m_end(0)
		, m_last(0)
	{
		if (n) resize(n);
	}

	buffer(buffer const& b)
		: m_begin(0)
		, m_end(0)
		, m_last(0)
	{
		if (b.size() == 0) return;
		resize(b.size());
		std::memcpy(m_begin, b.begin(), b.size());
	}

	buffer& operator=(buffer const& b)
	{
		if (&b == this) return *this;
		resize(b.size());
		std::memcpy(m_begin, b.begin(), b.size());
		return *this;
	}

	~buffer()
	{
		std::free(m_begin);
	}

	buffer::interval data() { return interval(m_begin, m_end); }
	buffer::const_interval data() const { return const_interval(m_begin, m_end); }

	void resize(std::size_t n)
	{
		reserve(n);
		m_end = m_begin + n;
	}

	void insert(char* point, char const* first, char const* last)
	{
		std::size_t p = point - m_begin;
		if (point == m_end)
		{
			resize(size() + last - first);
			std::memcpy(m_begin + p, first, last - first);
			return;
		}

		resize(size() + last - first);
		std::memmove(m_begin + p + (last - first), m_begin + p, last - first);
		std::memcpy(m_begin + p, first, last - first);
	}

	void erase(char* begin, char* end)
	{
		TORRENT_ASSERT(end <= m_end);
		TORRENT_ASSERT(begin >= m_begin);
		TORRENT_ASSERT(begin <= end);
	 	if (end == m_end)
		{
			resize(begin - m_begin);
			return;
		}
		std::memmove(begin, end, m_end - end);
		m_end = begin + (m_end - end);
	 }

	void clear() { m_end = m_begin; }
	std::size_t size() const { return m_end - m_begin; }
	std::size_t capacity() const { return m_last - m_begin; }
	void reserve(std::size_t n)
	{
		if (n <= capacity()) return;
		TORRENT_ASSERT(n > 0);

		std::size_t s = size();
		m_begin = (char*)std::realloc(m_begin, n);
		m_end = m_begin + s;
		m_last = m_begin + n;
	}

	bool empty() const { return m_begin == m_end; }
	char& operator[](std::size_t i) { TORRENT_ASSERT(i < size()); return m_begin[i]; }
	char const& operator[](std::size_t i) const { TORRENT_ASSERT(i < size()); return m_begin[i]; }

	char* begin() { return m_begin; }
	char const* begin() const { return m_begin; }
	char* end() { return m_end; }
	char const* end() const { return m_end; }

	void swap(buffer& b)
	{
		using std::swap;
		swap(m_begin, b.m_begin);
		swap(m_end, b.m_end);
		swap(m_last, b.m_last);
	}
private:
	char* m_begin; // first
	char* m_end; // one passed end of size
	char* m_last; // one passed end of allocation
};

}

#endif // LIBTORRENT_BUFFER_HPP

<|endoftext|>


<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#include "IncoherentAcquirer.hpp"
#include "common.hpp"
#include "Statistics.hpp"
#include <limits>

GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_ams, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_ams_bytes, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_blocked, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_blocked_ticks_total, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_network_ticks_total, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_wakeup_ticks_total, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_blocked_ticks_max, std::numeric_limits<uint64_t>::min());
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_blocked_ticks_min, std::numeric_limits<uint64_t>::min());
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_network_ticks_max, std::numeric_limits<uint64_t>::min());
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_network_ticks_min, std::numeric_limits<uint64_t>::min());
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_wakeup_ticks_max, std::numeric_limits<uint64_t>::min());
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_wakeup_ticks_min, std::numeric_limits<uint64_t>::min());

void IAStatistics::count_acquire_ams( uint64_t bytes ) {
  acquire_ams++;
  acquire_ams_bytes+=bytes;
}

void IAStatistics::record_wakeup_latency( int64_t start_time, int64_t network_time ) {
  acquire_blocked++;
  int64_t current_time = Grappa::timestamp();
  int64_t blocked_latency = current_time - start_time;
  int64_t wakeup_latency = current_time - network_time;
  acquire_blocked_ticks_total += blocked_latency;
  acquire_wakeup_ticks_total += wakeup_latency;
  if( blocked_latency > acquire_blocked_ticks_max )
    acquire_blocked_ticks_max = blocked_latency;
  if( blocked_latency < acquire_blocked_ticks_min )
    acquire_blocked_ticks_min = blocked_latency;
  if( wakeup_latency > acquire_wakeup_ticks_max )
    acquire_wakeup_ticks_max = wakeup_latency;
  if( wakeup_latency < acquire_wakeup_ticks_min )
    acquire_wakeup_ticks_min = wakeup_latency;
}

void IAStatistics::record_network_latency( int64_t start_time ) {
  int64_t current_time = Grappa::timestamp();
  int64_t latency = current_time - start_time;
  acquire_network_ticks_total += latency;
  if( latency > acquire_network_ticks_max )
    acquire_network_ticks_max = latency;
  if( latency < acquire_network_ticks_min )
    acquire_network_ticks_min = latency;
}

<commit_msg>fix max min stats and consolidate in cache acquirer<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#include "IncoherentAcquirer.hpp"
#include "common.hpp"
#include "Statistics.hpp"
#include <limits>

GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_ams, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_ams_bytes, 0);
GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, acquire_blocked, 0);
GRAPPA_DEFINE_STAT(SummarizingStatistic<uint64_t>, acquire_blocked_ticks_total, 0);
GRAPPA_DEFINE_STAT(SummarizingStatistic<uint64_t>, acquire_network_ticks_total, 0);
GRAPPA_DEFINE_STAT(SummarizingStatistic<uint64_t>, acquire_wakeup_ticks_total, 0);

void IAStatistics::count_acquire_ams( uint64_t bytes ) {
  acquire_ams++;
  acquire_ams_bytes+=bytes;
}

void IAStatistics::record_wakeup_latency( int64_t start_time, int64_t network_time ) {
  acquire_blocked++;
  int64_t current_time = Grappa::timestamp();
  int64_t blocked_latency = current_time - start_time;
  int64_t wakeup_latency = current_time - network_time;
  acquire_blocked_ticks_total += blocked_latency;
  acquire_wakeup_ticks_total += wakeup_latency;
}

void IAStatistics::record_network_latency( int64_t start_time ) {
  int64_t current_time = Grappa::timestamp();
  int64_t latency = current_time - start_time;
  acquire_network_ticks_total += latency;
}

<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkQuadraticEdge.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 "vtkQuadraticEdge.h"

#include "vtkObjectFactory.h"
#include "vtkMath.h"
#include "vtkLine.h"
#include "vtkDoubleArray.h"
#include "vtkPoints.h"

vtkStandardNewMacro(vtkQuadraticEdge);

//----------------------------------------------------------------------------
// Construct the line with two points.
vtkQuadraticEdge::vtkQuadraticEdge()
{
  this->Scalars = vtkDoubleArray::New();
  this->Scalars->SetNumberOfTuples(2);
  this->Points->SetNumberOfPoints(3);
  this->PointIds->SetNumberOfIds(3);
  for (int i = 0; i < 3; i++)
    {
    this->Points->SetPoint(i, 0.0, 0.0, 0.0);
    this->PointIds->SetId(i,0);
    }
  this->Line = vtkLine::New();
}

//----------------------------------------------------------------------------
vtkQuadraticEdge::~vtkQuadraticEdge()
{
  this->Line->Delete();
  this->Scalars->Delete();
}

//----------------------------------------------------------------------------
int vtkQuadraticEdge::EvaluatePosition(double* x, double* closestPoint,
                                       int& subId, double pcoords[3],
                                       double& minDist2, double *weights)
{
  double closest[3];
  double pc[3], dist2;
  int ignoreId, i, returnStatus, status;
  double lineWeights[2];

  pcoords[1] = pcoords[2] = 0.0;

  returnStatus = -1;
  weights[0] = 0.0;
  for (minDist2=VTK_DOUBLE_MAX,i=0; i < 2; i++)
    {
    if ( i == 0)
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(0));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(2));
      }
    else
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(2));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(1));
      }

    status = this->Line->EvaluatePosition(x,closest,ignoreId,pc,
                                          dist2,lineWeights);
    if ( status != -1 && dist2 < minDist2 )
      {
      returnStatus = status;
      minDist2 = dist2;
      subId = i;
      pcoords[0] = pc[0];
      }
    }

  // adjust parametric coordinate
  if ( returnStatus != -1 )
    {
    if ( subId == 0 ) //first part
      {
      pcoords[0] = pcoords[0]/2.0;
      }
    else
      {
      pcoords[0] = 0.5 + pcoords[0]/2.0;
      }
    if(closestPoint!=0)
      {
      // Compute both closestPoint and weights
      this->EvaluateLocation(subId,pcoords,closestPoint,weights);
      }
    else
      {
      // Compute weights only
      this->InterpolationFunctions(pcoords,weights);
      }
    }

  return returnStatus;
}

//----------------------------------------------------------------------------
void vtkQuadraticEdge::EvaluateLocation(int& vtkNotUsed(subId),
                                        double pcoords[3],
                                        double x[3], double *weights)
{
  int i;
  double a0[3], a1[3], a2[3];
  this->Points->GetPoint(0, a0);
  this->Points->GetPoint(1, a1);
  this->Points->GetPoint(2, a2); //midside node

  this->InterpolationFunctions(pcoords,weights);

  for (i=0; i<3; i++)
    {
    x[i] = a0[i]*weights[0] + a1[i]*weights[1] + a2[i]*weights[2];
    }
}

//----------------------------------------------------------------------------
int vtkQuadraticEdge::CellBoundary(int subId, double pcoords[3],
                                   vtkIdList *pts)
{
  return this->Line->CellBoundary(subId, pcoords, pts);
}

//----------------------------------------------------------------------------
static int LinearLines[2][2] = { {0,2}, {2,1} };

void vtkQuadraticEdge::Contour(double value, vtkDataArray *cellScalars,
                               vtkIncrementalPointLocator *locator, vtkCellArray *verts,
                               vtkCellArray *lines, vtkCellArray *polys,
                               vtkPointData *inPd, vtkPointData *outPd,
                               vtkCellData *inCd, vtkIdType cellId,
                               vtkCellData *outCd)
{
  for (int i=0; i < 2; i++) //for each subdivided line
    {
    for ( int j=0; j<2; j++) //for each of the four vertices of the line
      {
      this->Line->Points->SetPoint(j,this->Points->GetPoint(LinearLines[i][j]));
      this->Line->PointIds->SetId(j,this->PointIds->GetId(LinearLines[i][j]));
      this->Scalars->SetValue(j,cellScalars->GetTuple1(LinearLines[i][j]));
      }
    this->Line->Contour(value, this->Scalars, locator, verts,
                       lines, polys, inPd, outPd, inCd, cellId, outCd);
    }
}

//----------------------------------------------------------------------------
// Line-line intersection. Intersection has to occur within [0,1] parametric
// coordinates and with specified tolerance.

// The following arguments were modified to avoid warnings:
// double p1[3], double p2[3], double x[3], double pcoords[3],

int vtkQuadraticEdge::IntersectWithLine(double p1[3], double p2[3],
                                        double tol, double& t,
                                        double x[3], double pcoords[3],
                                        int& subId)
{
  int subTest, numLines=2;

  for (subId=0; subId < numLines; subId++)
    {
    if ( subId == 0)
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(0));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(2));
      }
    else
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(2));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(1));
      }

    if ( this->Line->IntersectWithLine(p1, p2, tol, t, x, pcoords, subTest) )
      {
      return 1;
      }
    }

  return 0;
}

//----------------------------------------------------------------------------
int vtkQuadraticEdge::Triangulate(int vtkNotUsed(index), vtkIdList *ptIds,
                                  vtkPoints *pts)
{
  pts->Reset();
  ptIds->Reset();

  // The first line
  ptIds->InsertId(0,this->PointIds->GetId(0));
  pts->InsertPoint(0,this->Points->GetPoint(0));

  ptIds->InsertId(1,this->PointIds->GetId(2));
  pts->InsertPoint(1,this->Points->GetPoint(2));

  // The second line
  ptIds->InsertId(2,this->PointIds->GetId(2));
  pts->InsertPoint(2,this->Points->GetPoint(2));

  ptIds->InsertId(3,this->PointIds->GetId(1));
  pts->InsertPoint(3,this->Points->GetPoint(1));

  return 1;
}

//----------------------------------------------------------------------------
void vtkQuadraticEdge::Derivatives(int vtkNotUsed(subId),
                                   double pcoords[3], double *values,
                                   int dim, double *derivs)
{
  double x0[3], x1[3], x2[3];
  this->Points->GetPoint(0, x0);
  this->Points->GetPoint(1, x1);
  this->Points->GetPoint(2, x2); //midside node

  // set up Jacobian matrix and inverse matrix
  double *jTj[3], jTj0[3], jTj1[3], jTj2[3];
  jTj[0] = jTj0; jTj[1] = jTj1; jTj[2] = jTj2;
  double *jI[3], jI0[3], jI1[3], jI2[3];
  jI[0] = jI0; jI[1] = jI1; jI[2] = jI2;
  /*
  double *iI[3], iI0[3], iI1[3], iI2[3];
  iI[0] = iI0; iI[1] = iI1; iI[2] = iI2;
  */
  // Compute dx/dt, dy/dt, dz/dt
  this->InterpolationDerivs(pcoords,derivs);
  double dxdt = x0[0]*derivs[0] + x1[0]*derivs[1] + x2[0]*derivs[2];
  double dydt = x0[1]*derivs[0] + x1[1]*derivs[1] + x2[1]*derivs[2];
  double dzdt = x0[2]*derivs[0] + x1[2]*derivs[1] + x2[2]*derivs[2];

  // Compute the pseudo inverse (we are dealing with an overconstrained system,
  // i.e., a non-square Jacobian matrix). The pseudo inverse is ((jT*j)-1)*jT
  // with jT Jacobian transpose, -1 notation means inverse.
  // Compute jT * j
  jTj[0][0] = dxdt*dxdt;
  jTj[0][1] = dxdt*dydt;
  jTj[0][2] = dxdt*dzdt;
  jTj[1][0] = dydt*dxdt;
  jTj[1][1] = dydt*dydt;
  jTj[1][2] = dydt*dzdt;
  jTj[2][0] = dzdt*dxdt;
  jTj[2][1] = dzdt*dydt;
  jTj[2][2] = dzdt*dzdt;

  // Compute (jT * j) inverse
  // now find the inverse
  if ( vtkMath::InvertMatrix(jTj,jI,3) == 0 )
    {
    vtkErrorMacro(<<"Jacobian inverse not found");
    return;
    }

  // Multiply inverse by transpose (jT * j) * jT to yield pseudo inverse.
  // Here the pseudo inverse is a 3x1 matrix.
  double inv[3];
  inv[0] = jI[0][0]*dxdt + jI[0][1]*dydt + jI[0][2]*dzdt;
  inv[1] = jI[1][0]*dxdt + jI[1][1]*dydt + jI[1][2]*dzdt;
  inv[2] = jI[2][0]*dxdt + jI[2][1]*dydt + jI[2][2]*dzdt;

  //now compute the derivates of the data values
  double sum;
  int i, j, k;
  for (k=0; k<dim; k++)
    {
    sum = 0.0;
    for ( i=0; i < 3; i++) //loop over interp. function derivatives
      {
      sum += derivs[i] * values[dim*i + k];
      }
    for (j=0; j < 3; j++) //loop over derivative directions
      {
      derivs[3*k + j] = sum*inv[j];
      }
    }
}

//----------------------------------------------------------------------------
// Clip this quadratic edge using scalar value provided. Like contouring,
// except that it cuts the edge to produce linear line segments.
void vtkQuadraticEdge::Clip(double value, vtkDataArray *cellScalars,
                            vtkIncrementalPointLocator *locator, vtkCellArray *lines,
                            vtkPointData *inPd, vtkPointData *outPd,
                            vtkCellData *inCd, vtkIdType cellId,
                            vtkCellData *outCd, int insideOut)
{
  for (int i=0; i < 2; i++) //for each subdivided line
    {
    for ( int j=0; j<2; j++) //for each of the four vertices of the line
      {
      this->Line->Points->SetPoint(j,this->Points->GetPoint(LinearLines[i][j]));
      this->Line->PointIds->SetId(j,this->PointIds->GetId(LinearLines[i][j]));
      this->Scalars->SetValue(j,cellScalars->GetTuple1(LinearLines[i][j]));
      }
    this->Line->Clip(value, this->Scalars, locator, lines, inPd, outPd,
                     inCd, cellId, outCd, insideOut);
    }
}

//----------------------------------------------------------------------------
// Compute interpolation functions. Node [2] is the mid-edge node.
void vtkQuadraticEdge::InterpolationFunctions(double pcoords[3],
                                              double weights[3])
{
  double r = pcoords[0];

  weights[0] = 2.0 * (r - 0.5) * (r - 1.0);
  weights[1] = 2.0 * r * (r - 0.5);
  weights[2] = 4.0 * r * (1.0 - r);
}

//----------------------------------------------------------------------------
// Derivatives in parametric space.
void vtkQuadraticEdge::InterpolationDerivs(double pcoords[3], double derivs[3])
{
  double r = pcoords[0];

  derivs[0] = 4.0 * r - 3.0;
  derivs[1] = 4.0 * r - 1.0;
  derivs[2] = 4.0 - r * 8.0;
}

//----------------------------------------------------------------------------
static double vtkQEdgeCellPCoords[9] = {0.0,0.0,0.0, 1.0,0.0,0.0, 0.5,0.0,0.0};
double *vtkQuadraticEdge::GetParametricCoords()
{
  return vtkQEdgeCellPCoords;
}

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

  os << indent << "Line:\n";
  this->Line->PrintSelf(os,indent.GetNextIndent());
}
<commit_msg>vtkQuadraticEdge: remove broken Derivatives implementation<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkQuadraticEdge.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 "vtkQuadraticEdge.h"

#include "vtkObjectFactory.h"
#include "vtkMath.h"
#include "vtkLine.h"
#include "vtkDoubleArray.h"
#include "vtkPoints.h"

vtkStandardNewMacro(vtkQuadraticEdge);

//----------------------------------------------------------------------------
// Construct the line with two points.
vtkQuadraticEdge::vtkQuadraticEdge()
{
  this->Scalars = vtkDoubleArray::New();
  this->Scalars->SetNumberOfTuples(2);
  this->Points->SetNumberOfPoints(3);
  this->PointIds->SetNumberOfIds(3);
  for (int i = 0; i < 3; i++)
    {
    this->Points->SetPoint(i, 0.0, 0.0, 0.0);
    this->PointIds->SetId(i,0);
    }
  this->Line = vtkLine::New();
}

//----------------------------------------------------------------------------
vtkQuadraticEdge::~vtkQuadraticEdge()
{
  this->Line->Delete();
  this->Scalars->Delete();
}

//----------------------------------------------------------------------------
int vtkQuadraticEdge::EvaluatePosition(double* x, double* closestPoint,
                                       int& subId, double pcoords[3],
                                       double& minDist2, double *weights)
{
  double closest[3];
  double pc[3], dist2;
  int ignoreId, i, returnStatus, status;
  double lineWeights[2];

  pcoords[1] = pcoords[2] = 0.0;

  returnStatus = -1;
  weights[0] = 0.0;
  for (minDist2=VTK_DOUBLE_MAX,i=0; i < 2; i++)
    {
    if ( i == 0)
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(0));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(2));
      }
    else
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(2));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(1));
      }

    status = this->Line->EvaluatePosition(x,closest,ignoreId,pc,
                                          dist2,lineWeights);
    if ( status != -1 && dist2 < minDist2 )
      {
      returnStatus = status;
      minDist2 = dist2;
      subId = i;
      pcoords[0] = pc[0];
      }
    }

  // adjust parametric coordinate
  if ( returnStatus != -1 )
    {
    if ( subId == 0 ) //first part
      {
      pcoords[0] = pcoords[0]/2.0;
      }
    else
      {
      pcoords[0] = 0.5 + pcoords[0]/2.0;
      }
    if(closestPoint!=0)
      {
      // Compute both closestPoint and weights
      this->EvaluateLocation(subId,pcoords,closestPoint,weights);
      }
    else
      {
      // Compute weights only
      this->InterpolationFunctions(pcoords,weights);
      }
    }

  return returnStatus;
}

//----------------------------------------------------------------------------
void vtkQuadraticEdge::EvaluateLocation(int& vtkNotUsed(subId),
                                        double pcoords[3],
                                        double x[3], double *weights)
{
  int i;
  double a0[3], a1[3], a2[3];
  this->Points->GetPoint(0, a0);
  this->Points->GetPoint(1, a1);
  this->Points->GetPoint(2, a2); //midside node

  this->InterpolationFunctions(pcoords,weights);

  for (i=0; i<3; i++)
    {
    x[i] = a0[i]*weights[0] + a1[i]*weights[1] + a2[i]*weights[2];
    }
}

//----------------------------------------------------------------------------
int vtkQuadraticEdge::CellBoundary(int subId, double pcoords[3],
                                   vtkIdList *pts)
{
  return this->Line->CellBoundary(subId, pcoords, pts);
}

//----------------------------------------------------------------------------
static int LinearLines[2][2] = { {0,2}, {2,1} };

void vtkQuadraticEdge::Contour(double value, vtkDataArray *cellScalars,
                               vtkIncrementalPointLocator *locator, vtkCellArray *verts,
                               vtkCellArray *lines, vtkCellArray *polys,
                               vtkPointData *inPd, vtkPointData *outPd,
                               vtkCellData *inCd, vtkIdType cellId,
                               vtkCellData *outCd)
{
  for (int i=0; i < 2; i++) //for each subdivided line
    {
    for ( int j=0; j<2; j++) //for each of the four vertices of the line
      {
      this->Line->Points->SetPoint(j,this->Points->GetPoint(LinearLines[i][j]));
      this->Line->PointIds->SetId(j,this->PointIds->GetId(LinearLines[i][j]));
      this->Scalars->SetValue(j,cellScalars->GetTuple1(LinearLines[i][j]));
      }
    this->Line->Contour(value, this->Scalars, locator, verts,
                       lines, polys, inPd, outPd, inCd, cellId, outCd);
    }
}

//----------------------------------------------------------------------------
// Line-line intersection. Intersection has to occur within [0,1] parametric
// coordinates and with specified tolerance.

// The following arguments were modified to avoid warnings:
// double p1[3], double p2[3], double x[3], double pcoords[3],

int vtkQuadraticEdge::IntersectWithLine(double p1[3], double p2[3],
                                        double tol, double& t,
                                        double x[3], double pcoords[3],
                                        int& subId)
{
  int subTest, numLines=2;

  for (subId=0; subId < numLines; subId++)
    {
    if ( subId == 0)
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(0));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(2));
      }
    else
      {
      this->Line->Points->SetPoint(0,this->Points->GetPoint(2));
      this->Line->Points->SetPoint(1,this->Points->GetPoint(1));
      }

    if ( this->Line->IntersectWithLine(p1, p2, tol, t, x, pcoords, subTest) )
      {
      return 1;
      }
    }

  return 0;
}

//----------------------------------------------------------------------------
int vtkQuadraticEdge::Triangulate(int vtkNotUsed(index), vtkIdList *ptIds,
                                  vtkPoints *pts)
{
  pts->Reset();
  ptIds->Reset();

  // The first line
  ptIds->InsertId(0,this->PointIds->GetId(0));
  pts->InsertPoint(0,this->Points->GetPoint(0));

  ptIds->InsertId(1,this->PointIds->GetId(2));
  pts->InsertPoint(1,this->Points->GetPoint(2));

  // The second line
  ptIds->InsertId(2,this->PointIds->GetId(2));
  pts->InsertPoint(2,this->Points->GetPoint(2));

  ptIds->InsertId(3,this->PointIds->GetId(1));
  pts->InsertPoint(3,this->Points->GetPoint(1));

  return 1;
}

//----------------------------------------------------------------------------
void vtkQuadraticEdge::Derivatives(int vtkNotUsed(subId),
                                       double vtkNotUsed(pcoords)[3],
                                       double *vtkNotUsed(values),
                                       int vtkNotUsed(dim),
                                       double *vtkNotUsed(derivs))
{
  // TODO - if the effort is justified, someone should implement a correct
  // version of this method
  vtkErrorMacro( "Derivatives() is not implemented for this cell.");
}

//----------------------------------------------------------------------------
// Clip this quadratic edge using scalar value provided. Like contouring,
// except that it cuts the edge to produce linear line segments.
void vtkQuadraticEdge::Clip(double value, vtkDataArray *cellScalars,
                            vtkIncrementalPointLocator *locator, vtkCellArray *lines,
                            vtkPointData *inPd, vtkPointData *outPd,
                            vtkCellData *inCd, vtkIdType cellId,
                            vtkCellData *outCd, int insideOut)
{
  for (int i=0; i < 2; i++) //for each subdivided line
    {
    for ( int j=0; j<2; j++) //for each of the four vertices of the line
      {
      this->Line->Points->SetPoint(j,this->Points->GetPoint(LinearLines[i][j]));
      this->Line->PointIds->SetId(j,this->PointIds->GetId(LinearLines[i][j]));
      this->Scalars->SetValue(j,cellScalars->GetTuple1(LinearLines[i][j]));
      }
    this->Line->Clip(value, this->Scalars, locator, lines, inPd, outPd,
                     inCd, cellId, outCd, insideOut);
    }
}

//----------------------------------------------------------------------------
// Compute interpolation functions. Node [2] is the mid-edge node.
void vtkQuadraticEdge::InterpolationFunctions(double pcoords[3],
                                              double weights[3])
{
  double r = pcoords[0];

  weights[0] = 2.0 * (r - 0.5) * (r - 1.0);
  weights[1] = 2.0 * r * (r - 0.5);
  weights[2] = 4.0 * r * (1.0 - r);
}

//----------------------------------------------------------------------------
// Derivatives in parametric space.
void vtkQuadraticEdge::InterpolationDerivs(double pcoords[3], double derivs[3])
{
  double r = pcoords[0];

  derivs[0] = 4.0 * r - 3.0;
  derivs[1] = 4.0 * r - 1.0;
  derivs[2] = 4.0 - r * 8.0;
}

//----------------------------------------------------------------------------
static double vtkQEdgeCellPCoords[9] = {0.0,0.0,0.0, 1.0,0.0,0.0, 0.5,0.0,0.0};
double *vtkQuadraticEdge::GetParametricCoords()
{
  return vtkQEdgeCellPCoords;
}

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

  os << indent << "Line:\n";
  this->Line->PrintSelf(os,indent.GetNextIndent());
}
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <iterator>
#include <functional>

namespace helene
{

template <class PropertyType>
class persistent_iterator_
{
    template <class NodeType, class EdgeType>
    friend class dag;

public:
    typedef typename std::vector<PropertyType>::size_type size_type;

    typedef typename std::vector<PropertyType>::difference_type difference_type;
    typedef PropertyType value_type;
    typedef PropertyType* pointer;
    typedef PropertyType& reference;

public:
    persistent_iterator_(size_type current_index,
                         std::vector<PropertyType>& nodes)
        : current_index_(current_index), nodes_ref_(nodes)
    {
    }

public:
    // Iterator concept member functions
    reference operator*()
    {
        return nodes_ref_.get()[current_index_];
    }

    persistent_iterator_& operator++()
    {
        ++current_index_;
        return *this;
    }

    // EqualityComparable
    bool
    operator==(const persistent_iterator_& other) const
    {
        return (current_index_ == other.current_index_) &&
               (&(nodes_ref_.get()) == &(other.nodes_ref_.get()));
    }

    // InputIterator
    bool
    operator!=(const persistent_iterator_& other) const
    {
        return !(*this == other);
    }

    pointer operator->()
    {
        return &(nodes_ref_.get()[current_index_]);
    }

    persistent_iterator_ operator++(int)
    {
        auto temp = *this;
        ++(*this);

        return temp;
    }

    // BidirectionalIterator
    persistent_iterator_& operator--()
    {
        --current_index_;
        return *this;
    }

    persistent_iterator_ operator--(int)
    {
        auto temp = *this;
        --(*this);
        return temp;
    }

    // RandomAccessIterator
    persistent_iterator_&
    operator+=(difference_type n)
    {
        current_index_ += n;
        return *this;
    }

    persistent_iterator_
    operator+(difference_type n) const
    {
        return persistent_iterator_(current_index_ + n, nodes_ref_);
    }

    friend persistent_iterator_
    operator+(difference_type lhs, const persistent_iterator_& rhs)
    {
        return rhs + lhs;
    }

    persistent_iterator_&
    operator-=(difference_type n)
    {
        current_index_ -= n;
        return *this;
    }

    persistent_iterator_
    operator-(difference_type n) const
    {
        return persistent_iterator_(current_index_ - n, nodes_ref_);
    }

    difference_type
    operator-(const persistent_iterator_& other) const
    {
        return current_index_ - other.current_index_;
    }

    reference operator[](difference_type n)
    {
        return nodes_ref_.get()[current_index_ + n];
    }

    bool
    operator<(const persistent_iterator_& other) const
    {
        return current_index_ < other.current_index_;
    }

    bool
    operator>(const persistent_iterator_& other) const
    {
        return current_index_ > other.current_index_;
    }

    bool
    operator<=(const persistent_iterator_& other) const
    {
        return current_index_ <= other.current_index_;
    }

    bool
    operator>=(const persistent_iterator_& other) const
    {
        return current_index_ >= other.current_index_;
    }

private:
    std::reference_wrapper<std::vector<PropertyType>> nodes_ref_;
    size_type current_index_;
};

template <class NodeType, class EdgeType>
class dag
{
public:
    ////////////////////////////////////////////////////////////////////////////
    // public typedefs

    // node typedefs
    typedef NodeType value_type;
    typedef NodeType& reference;
    typedef const NodeType& const_reference;
    typedef typename std::vector<NodeType>::difference_type difference_type;
    typedef typename std::vector<NodeType>::size_type size_type;

    typedef persistent_iterator_<NodeType> iterator;

    // edge typedefs
    typedef EdgeType edge_value_type;
    typedef EdgeType& edge_reference;
    typedef const EdgeType& const_edge_reference;
    typedef typename std::vector<EdgeType>::size_type edge_size_type;
    typedef
        typename std::vector<EdgeType>::difference_type edge_difference_type;

    typedef persistent_iterator_<EdgeType> edge_iterator;

private:
    ////////////////////////////////////////////////////////////////////////////
    // internal classes

    // indices to properties of the associated edge
    struct edge
    {
        edge(size_type from, size_type to)
            : from_property(from), to_property(to)
        {
        }

        size_type from_property;
        size_type to_property;

        bool
        operator==(const edge& other) const
        {
            return (from_property == other.from_property) &&
                   (to_property == other.to_property);
        }
    };

public:
    ////////////////////////////////////////////////////////////////////////////
    // Container concept member functions

    dag() = default;
    dag(const dag&) = default;

    dag& operator=(const dag&) = default;

    iterator
    begin()
    {
        return iterator(0, node_properties_);
    }

    iterator
    end()
    {
        return iterator(node_properties_.size(), node_properties_);
    }

    edge_iterator
    edge_begin()
    {
        return edge_iterator(0, edge_properties_);
    }

    edge_iterator
    edge_end()
    {
        return edge_iterator(edge_properties_.size(), edge_properties_);
    }

    bool
    operator==(const dag& other) const
    {
        return (node_properties_ == other.node_properties_) &&
               (edge_properties_ == other.edge_properties_) &&
               (edges_ == other.edges_);
    }

    bool
    operator!=(const dag& other) const
    {
        return !(*this == other);
    }

    void
    swap(dag& other)
    {
        node_properties_.swap(other.node_properties_);
        edge_properties_.swap(other.edge_properties_);
        edges_.swap(other.edges_);
    }

    size_type
    size() const
    {
        return node_properties_.size();
    }

    edge_size_type
    edge_size() const
    {
        return edge_properties_.size();
    }

    bool
    empty() const
    {
        return node_properties_.empty();
    }

    bool
    edge_empty() const
    {
        return edge_properties_.empty();
    }

public:
    ////////////////////////////////////////////////////////////////////////////
    // dag specific member functions

    // Add node
    iterator
    add_node(const NodeType& prop)
    {
        const auto index = node_properties_.size();
        node_properties_.push_back(prop);
        return iterator(index, node_properties_);
    }

    // Add edge between nodes.
    // If edge introduces cycle edge will not be inserted.
    // Returns iterator to edge property or edge_end() if edge was prevented
    // from being inserted.
    edge_iterator
    add_edge(iterator from, iterator to, const EdgeType& prop)
    {
        const auto index = edge_properties_.size();
        const auto from_index = from.current_index_;
        const auto to_index = to.current_index_;
        edge_properties_.push_back(prop);
        edges_.emplace_back(from_index, to_index);

        return edge_iterator(index, edge_properties_);
    }

    std::pair<iterator, iterator>
    edge_endpoints(edge_iterator ed)
    {
        const auto edge_index = ed.current_index_;

        return std::make_pair(
            iterator(edges_[edge_index].from_property, node_properties_),
            iterator(edges_[edge_index].to_property, node_properties_));
    }

private:
    std::vector<NodeType> node_properties_;
    std::vector<EdgeType> edge_properties_;

    std::vector<edge> edges_;
};
}

namespace std
{
template <class PropertyType>
struct iterator_traits<helene::persistent_iterator_<PropertyType>>
{
    typedef typename helene::persistent_iterator_<PropertyType>::difference_type
        difference_type;

    typedef typename helene::persistent_iterator_<PropertyType>::value_type
        value_type;

    typedef
        typename helene::persistent_iterator_<PropertyType>::pointer pointer;

    typedef typename helene::persistent_iterator_<PropertyType>::reference
        reference;

    typedef random_access_iterator_tag iterator_category;
};
}

<commit_msg>Comments. 	modified:   include/dag.hpp<commit_after>#pragma once

#include <vector>
#include <iterator>
#include <functional>

namespace helene
{

template <class PropertyType>
class persistent_iterator_
{
    template <class NodeType, class EdgeType>
    friend class dag;

public:
    typedef typename std::vector<PropertyType>::size_type size_type;

    typedef typename std::vector<PropertyType>::difference_type difference_type;
    typedef PropertyType value_type;
    typedef PropertyType* pointer;
    typedef PropertyType& reference;

public:
    persistent_iterator_(size_type current_index,
                         std::vector<PropertyType>& nodes)
        : current_index_(current_index), nodes_ref_(nodes)
    {
    }

public:
    // Iterator concept member functions
    reference operator*()
    {
        return nodes_ref_.get()[current_index_];
    }

    persistent_iterator_& operator++()
    {
        ++current_index_;
        return *this;
    }

    // EqualityComparable
    bool
    operator==(const persistent_iterator_& other) const
    {
        return (current_index_ == other.current_index_) &&
               (&(nodes_ref_.get()) == &(other.nodes_ref_.get()));
    }

    // InputIterator
    bool
    operator!=(const persistent_iterator_& other) const
    {
        return !(*this == other);
    }

    pointer operator->()
    {
        return &(nodes_ref_.get()[current_index_]);
    }

    persistent_iterator_ operator++(int)
    {
        auto temp = *this;
        ++(*this);

        return temp;
    }

    // BidirectionalIterator
    persistent_iterator_& operator--()
    {
        --current_index_;
        return *this;
    }

    persistent_iterator_ operator--(int)
    {
        auto temp = *this;
        --(*this);
        return temp;
    }

    // RandomAccessIterator
    persistent_iterator_&
    operator+=(difference_type n)
    {
        current_index_ += n;
        return *this;
    }

    persistent_iterator_
    operator+(difference_type n) const
    {
        return persistent_iterator_(current_index_ + n, nodes_ref_);
    }

    friend persistent_iterator_
    operator+(difference_type lhs, const persistent_iterator_& rhs)
    {
        return rhs + lhs;
    }

    persistent_iterator_&
    operator-=(difference_type n)
    {
        current_index_ -= n;
        return *this;
    }

    persistent_iterator_
    operator-(difference_type n) const
    {
        return persistent_iterator_(current_index_ - n, nodes_ref_);
    }

    difference_type
    operator-(const persistent_iterator_& other) const
    {
        return current_index_ - other.current_index_;
    }

    reference operator[](difference_type n)
    {
        return nodes_ref_.get()[current_index_ + n];
    }

    bool
    operator<(const persistent_iterator_& other) const
    {
        return current_index_ < other.current_index_;
    }

    bool
    operator>(const persistent_iterator_& other) const
    {
        return current_index_ > other.current_index_;
    }

    bool
    operator<=(const persistent_iterator_& other) const
    {
        return current_index_ <= other.current_index_;
    }

    bool
    operator>=(const persistent_iterator_& other) const
    {
        return current_index_ >= other.current_index_;
    }

private:
    std::reference_wrapper<std::vector<PropertyType>> nodes_ref_;
    size_type current_index_;
};

template <class NodeType, class EdgeType>
class dag
{
public:
    ////////////////////////////////////////////////////////////////////////////
    // public typedefs

    // node typedefs
    typedef NodeType value_type;
    typedef NodeType& reference;
    typedef const NodeType& const_reference;
    typedef typename std::vector<NodeType>::difference_type difference_type;
    typedef typename std::vector<NodeType>::size_type size_type;

    typedef persistent_iterator_<NodeType> iterator;

    // edge typedefs
    typedef EdgeType edge_value_type;
    typedef EdgeType& edge_reference;
    typedef const EdgeType& const_edge_reference;
    typedef typename std::vector<EdgeType>::size_type edge_size_type;
    typedef
        typename std::vector<EdgeType>::difference_type edge_difference_type;

    typedef persistent_iterator_<EdgeType> edge_iterator;

private:
    ////////////////////////////////////////////////////////////////////////////
    // internal classes

    // indices to properties of the associated edge
    struct edge
    {
        edge(size_type from, size_type to)
            : from_property(from), to_property(to)
        {
        }

        size_type from_property;
        size_type to_property;

        bool
        operator==(const edge& other) const
        {
            return (from_property == other.from_property) &&
                   (to_property == other.to_property);
        }
    };

public:
    ////////////////////////////////////////////////////////////////////////////
    // Container concept member functions

    dag() = default;
    dag(const dag&) = default;

    dag& operator=(const dag&) = default;

    iterator
    begin()
    {
        return iterator(0, node_properties_);
    }

    iterator
    end()
    {
        return iterator(node_properties_.size(), node_properties_);
    }

    edge_iterator
    edge_begin()
    {
        return edge_iterator(0, edge_properties_);
    }

    edge_iterator
    edge_end()
    {
        return edge_iterator(edge_properties_.size(), edge_properties_);
    }

    bool
    operator==(const dag& other) const
    {
        return (node_properties_ == other.node_properties_) &&
               (edge_properties_ == other.edge_properties_) &&
               (edges_ == other.edges_);
    }

    bool
    operator!=(const dag& other) const
    {
        return !(*this == other);
    }

    void
    swap(dag& other)
    {
        node_properties_.swap(other.node_properties_);
        edge_properties_.swap(other.edge_properties_);
        edges_.swap(other.edges_);
    }

    size_type
    size() const
    {
        return node_properties_.size();
    }

    edge_size_type
    edge_size() const
    {
        return edge_properties_.size();
    }

    bool
    empty() const
    {
        return node_properties_.empty();
    }

    bool
    edge_empty() const
    {
        return edge_properties_.empty();
    }

public:
    ////////////////////////////////////////////////////////////////////////////
    // dag specific member functions

    // Add node
    iterator
    add_node(const NodeType& prop)
    {
        const auto index = node_properties_.size();
        node_properties_.push_back(prop);
        return iterator(index, node_properties_);
    }

    // Add edge between nodes.
    // If edge introduces cycle edge will not be inserted.
    // Returns iterator to edge property or edge_end() if edge was prevented
    // from being inserted.
    edge_iterator
    add_edge(iterator from, iterator to, const EdgeType& prop)
    {
        const auto index = edge_properties_.size();
        const auto from_index = from.current_index_;
        const auto to_index = to.current_index_;
        edge_properties_.push_back(prop);
        edges_.emplace_back(from_index, to_index);

        return edge_iterator(index, edge_properties_);
    }

    // returns pair of iterator to nodes connected by edge ed <from , to>
    std::pair<iterator, iterator>
    edge_endpoints(edge_iterator ed)
    {
        const auto edge_index = ed.current_index_;

        return std::make_pair(
            iterator(edges_[edge_index].from_property, node_properties_),
            iterator(edges_[edge_index].to_property, node_properties_));
    }

private:
    std::vector<NodeType> node_properties_;
    std::vector<EdgeType> edge_properties_;

    std::vector<edge> edges_;
};
}

namespace std
{
template <class PropertyType>
struct iterator_traits<helene::persistent_iterator_<PropertyType>>
{
    typedef typename helene::persistent_iterator_<PropertyType>::difference_type
        difference_type;

    typedef typename helene::persistent_iterator_<PropertyType>::value_type
        value_type;

    typedef
        typename helene::persistent_iterator_<PropertyType>::pointer pointer;

    typedef typename helene::persistent_iterator_<PropertyType>::reference
        reference;

    typedef random_access_iterator_tag iterator_category;
};
}

<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2015 Pedro Côrte-Real
    Copyright (C) 2017 Axel Waggershauser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "tiff/TiffIFD.h"
#include "common/Common.h"            // for getHostEndianness, uint32, make_...
#include "common/NORangesSet.h"       // for NORangesSet
#include "common/RawspeedException.h" // for RawspeedException
#include "io/IOException.h"           // for IOException
#include "tiff/TiffEntry.h"           // for TiffEntry
#include "tiff/TiffTag.h"             // for TiffTag, ::DNGPRIVATEDATA, ::EXI...
#include <algorithm>                  // for move
#include <cstdint>                    // for UINT32_MAX
#include <map>                        // for map, _Rb_tree_const_iterator, al...
#include <memory>                     // for default_delete, unique_ptr
#include <string>                     // for operator==, string, basic_string
#include <utility>                    // for pair
#include <vector>                     // for vector

using std::string;
using std::vector;

namespace rawspeed {

void TiffIFD::parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs) {
  TiffEntryOwner t;

  auto origPos = bs->getPosition();

  try {
    t = std::make_unique<TiffEntry>(this, bs);
  } catch (IOException&) { // Ignore unparsable entry
    // fix probably broken position due to interruption by exception
    // i.e. setting it to the next entry.
    bs->setPosition(origPos + 12);
    return;
  }

  try {
    switch (t->tag) {
    case DNGPRIVATEDATA:
      add(parseDngPrivateData(ifds, t.get()));
      break;

    case MAKERNOTE:
    case MAKERNOTE_ALT:
      add(parseMakerNote(ifds, t.get()));
      break;

    case FUJI_RAW_IFD:
    case SUBIFDS:
    case EXIFIFDPOINTER:
      for (uint32 j = 0; j < t->count; j++)
        add(std::make_unique<TiffIFD>(this, ifds, *bs, t->getU32(j)));
      break;

    default:
      add(move(t));
    }
  } catch (RawspeedException&) { // Unparsable private data are added as entries
    add(move(t));
  }
}

TiffIFD::TiffIFD(TiffIFD* parent_) : parent(parent_) {}

TiffIFD::TiffIFD(TiffIFD* parent_, NORangesSet<Buffer>* ifds,
                 const DataBuffer& data, uint32 offset)
    : TiffIFD(parent_) {

  // see TiffParser::parse: UINT32_MAX is used to mark the "virtual" top level
  // TiffRootIFD in a tiff file
  if (offset == UINT32_MAX)
    return;

  checkOverflow();

  ByteStream bs(data);
  bs.setPosition(offset);

  // Directory entries in this IFD
  auto numEntries = bs.getU16();

  // 2 bytes for entry count
  // each entry is 12 bytes
  // 4-byte offset to the next IFD at the end
  const auto IFDFullSize = 2 + 4 + 12 * numEntries;
  const Buffer IFDBuf(data.getSubView(offset, IFDFullSize));
  if (ifds && !ifds->emplace(IFDBuf).second)
    ThrowTPE("Two IFD's overlap. Raw corrupt!");

  for (uint32 i = 0; i < numEntries; i++)
    parseIFDEntry(ifds, &bs);

  nextIFD = bs.getU32();
}

TiffRootIFDOwner TiffIFD::parseDngPrivateData(NORangesSet<Buffer>* ifds,
                                              TiffEntry* t) {
  /*
  1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format).
  2. 4 bytes: an ASCII string ("MakN" for a Makernote),  indicating what sort of data is being stored here. Note that this is not zero-terminated.
  3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format).
  4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949).
  5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above).
  6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification.
  */
  ByteStream& bs = t->getData();
  if (!bs.skipPrefix("Adobe", 6))
    ThrowTPE("Not Adobe Private data");

  if (!bs.skipPrefix("MakN", 4))
    ThrowTPE("Not Makernote");

  bs.setByteOrder(Endianness::big);
  uint32 makerNoteSize = bs.getU32();
  if (makerNoteSize != bs.getRemainSize())
    ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt");

  bs.setByteOrder(getTiffByteOrder(bs, 0, "DNG makernote"));
  bs.skipBytes(2);

  uint32 makerNoteOffset = bs.getU32();
  makerNoteSize -= 6; // update size of orinial maker note, we skipped 2+4 bytes

  // Update the underlying buffer of t, such that the maker note data starts at its original offset
  bs.rebase(makerNoteOffset, makerNoteSize);

  return parseMakerNote(ifds, t);
}

/* This will attempt to parse makernotes and return it as an IFD */
TiffRootIFDOwner TiffIFD::parseMakerNote(NORangesSet<Buffer>* ifds,
                                         TiffEntry* t) {
  // go up the IFD tree and try to find the MAKE entry on each level.
  // we can not go all the way to the top first because this partial tree
  // is not yet added to the TiffRootIFD.
  TiffIFD* p = this;
  TiffEntry* makeEntry;
  do {
    makeEntry = p->getEntryRecursive(MAKE);
    p = p->parent;
  } while (!makeEntry && p);
  string make = makeEntry != nullptr ? trimSpaces(makeEntry->getString()) : "";

  ByteStream bs = t->getData();

  // helper function for easy setup of ByteStream buffer for the different maker note types
  // 'rebase' means position 0 of new stream equals current position
  // 'newPosition' is the position where the IFD starts
  // 'byteOrderOffset' is the position wher the 2 magic bytes (II/MM) may be found
  // 'context' is a string providing error information in case the byte order parsing should fail
  auto setup = [&bs](bool rebase, uint32 newPosition,
                     uint32 byteOrderOffset = 0,
                     const char *context = nullptr) {
    if (rebase)
      bs = bs.getSubStream(bs.getPosition(), bs.getRemainSize());
    if (context)
      bs.setByteOrder(getTiffByteOrder(bs, byteOrderOffset, context));
    bs.skipBytes(newPosition);
  };

  if (bs.hasPrefix("AOC\0", 4)) {
    setup(false, 6, 4, "Pentax makernote");
  } else if (bs.hasPrefix("PENTAX", 6)) {
    setup(true, 10, 8, "Pentax makernote");
  } else if (bs.hasPrefix("FUJIFILM\x0c\x00\x00\x00", 12)) {
    bs.setByteOrder(Endianness::little);
    setup(true, 12);
  } else if (bs.hasPrefix("Nikon\x00\x02", 7)) {
    // this is Nikon type 3 maker note format
    // TODO: implement Nikon type 1 maker note format
    // see http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html
    bs.skipBytes(10);
    setup(true, 8, 0, "Nikon makernote");
  } else if (bs.hasPrefix("OLYMPUS", 7)) { // new Olympus
    setup(true, 12);
  } else if (bs.hasPrefix("OLYMP", 5)) {   // old Olympus
    setup(true, 8);
  } else if (bs.hasPrefix("EPSON", 5)) {
    setup(false, 8);
  } else if (bs.hasPatternAt("Exif", 4, 6)) {
    // TODO: for none of the rawsamples.ch files from Panasonic is this true, instead their MakerNote start with "Panasonic"
    // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
    // This TIFF is 0 offset based
    setup(false, 20, 12, "Panosonic makernote");
  } else if (make == "SAMSUNG") {
    // Samsung has no identification in its MakerNote but starts with the IFD right away
    setup(true, 0);
  } else {
    // cerr << "default MakerNote from " << make << endl; // Canon, Nikon (type 2), Sony, Minolta, Ricoh, Leica, Hasselblad, etc.

    // At least one MAKE has not been handled explicitly and starts its MakerNote with an endian prefix: Kodak
    if (bs.skipPrefix("II", 2)) {
      bs.setByteOrder(Endianness::little);
    } else if (bs.skipPrefix("MM", 2)) {
      bs.setByteOrder(Endianness::big);
    }
  }

  // Attempt to parse the rest as an IFD
  return std::make_unique<TiffRootIFD>(this, ifds, bs, bs.getPosition());
}

std::vector<const TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) const {
  vector<const TiffIFD*> matchingIFDs;
  if (entries.find(tag) != entries.end()) {
    matchingIFDs.push_back(this);
  }
  for (auto& i : subIFDs) {
    vector<const TiffIFD*> t = i->getIFDsWithTag(tag);
    matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
  }
  return matchingIFDs;
}

const TiffIFD* TiffIFD::getIFDWithTag(TiffTag tag, uint32 index) const
{
  auto ifds = getIFDsWithTag(tag);
  if (index >= ifds.size())
    ThrowTPE("failed to find %u ifs with tag 0x%04x", index + 1, tag);
  return ifds[index];
}

TiffEntry* __attribute__((pure)) TiffIFD::getEntryRecursive(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i != entries.end()) {
    return i->second.get();
  }
  for (auto &j : subIFDs) {
    TiffEntry *entry = j->getEntryRecursive(tag);
    if (entry)
      return entry;
  }
  return nullptr;
}

void TiffIFD::checkOverflow() {
  TiffIFD* p = this;
  int i = 0;
  while ((p = p->parent) != nullptr) {
    i++;
    if (i > 5)
      ThrowTPE("TiffIFD cascading overflow.");
  }
}

void TiffIFD::add(TiffIFDOwner subIFD) {
  checkOverflow();
  if (subIFDs.size() > 100)
    ThrowTPE("TIFF file has too many SubIFDs, probably broken");
  subIFD->parent = this;
  subIFDs.push_back(move(subIFD));
}

void TiffIFD::add(TiffEntryOwner entry) {
  entry->parent = this;
  entries[entry->tag] = move(entry);
}

TiffEntry* TiffIFD::getEntry(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i == entries.end())
    ThrowTPE("Entry 0x%x not found.", tag);
  return i->second.get();
}

TiffID TiffRootIFD::getID() const
{
  TiffID id;
  auto makeE = getEntryRecursive(MAKE);
  auto modelE = getEntryRecursive(MODEL);

  if (!makeE)
    ThrowTPE("Failed to find MAKE entry.");
  if (!modelE)
    ThrowTPE("Failed to find MODEL entry.");

  id.make = trimSpaces(makeE->getString());
  id.model = trimSpaces(modelE->getString());

  return id;
}

} // namespace rawspeed
<commit_msg>TiffRootIFD: assert that NORangesSet is always passed.<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2015 Pedro Côrte-Real
    Copyright (C) 2017 Axel Waggershauser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "tiff/TiffIFD.h"
#include "common/Common.h"            // for getHostEndianness, uint32, make_...
#include "common/NORangesSet.h"       // for NORangesSet
#include "common/RawspeedException.h" // for RawspeedException
#include "io/IOException.h"           // for IOException
#include "tiff/TiffEntry.h"           // for TiffEntry
#include "tiff/TiffTag.h"             // for TiffTag, ::DNGPRIVATEDATA, ::EXI...
#include <algorithm>                  // for move
#include <cstdint>                    // for UINT32_MAX
#include <map>                        // for map, _Rb_tree_const_iterator, al...
#include <memory>                     // for default_delete, unique_ptr
#include <string>                     // for operator==, string, basic_string
#include <utility>                    // for pair
#include <vector>                     // for vector

using std::string;
using std::vector;

namespace rawspeed {

void TiffIFD::parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs) {
  assert(ifds);

  TiffEntryOwner t;

  auto origPos = bs->getPosition();

  try {
    t = std::make_unique<TiffEntry>(this, bs);
  } catch (IOException&) { // Ignore unparsable entry
    // fix probably broken position due to interruption by exception
    // i.e. setting it to the next entry.
    bs->setPosition(origPos + 12);
    return;
  }

  try {
    switch (t->tag) {
    case DNGPRIVATEDATA:
      add(parseDngPrivateData(ifds, t.get()));
      break;

    case MAKERNOTE:
    case MAKERNOTE_ALT:
      add(parseMakerNote(ifds, t.get()));
      break;

    case FUJI_RAW_IFD:
    case SUBIFDS:
    case EXIFIFDPOINTER:
      for (uint32 j = 0; j < t->count; j++)
        add(std::make_unique<TiffIFD>(this, ifds, *bs, t->getU32(j)));
      break;

    default:
      add(move(t));
    }
  } catch (RawspeedException&) { // Unparsable private data are added as entries
    add(move(t));
  }
}

TiffIFD::TiffIFD(TiffIFD* parent_) : parent(parent_) {}

TiffIFD::TiffIFD(TiffIFD* parent_, NORangesSet<Buffer>* ifds,
                 const DataBuffer& data, uint32 offset)
    : TiffIFD(parent_) {
  // see TiffParser::parse: UINT32_MAX is used to mark the "virtual" top level
  // TiffRootIFD in a tiff file
  if (offset == UINT32_MAX)
    return;

  assert(ifds);

  checkOverflow();

  ByteStream bs(data);
  bs.setPosition(offset);

  // Directory entries in this IFD
  auto numEntries = bs.getU16();

  // 2 bytes for entry count
  // each entry is 12 bytes
  // 4-byte offset to the next IFD at the end
  const auto IFDFullSize = 2 + 4 + 12 * numEntries;
  const Buffer IFDBuf(data.getSubView(offset, IFDFullSize));
  if (!ifds->emplace(IFDBuf).second)
    ThrowTPE("Two IFD's overlap. Raw corrupt!");

  for (uint32 i = 0; i < numEntries; i++)
    parseIFDEntry(ifds, &bs);

  nextIFD = bs.getU32();
}

TiffRootIFDOwner TiffIFD::parseDngPrivateData(NORangesSet<Buffer>* ifds,
                                              TiffEntry* t) {
  assert(ifds);

  /*
  1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format).
  2. 4 bytes: an ASCII string ("MakN" for a Makernote),  indicating what sort of data is being stored here. Note that this is not zero-terminated.
  3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format).
  4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949).
  5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above).
  6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification.
  */
  ByteStream& bs = t->getData();
  if (!bs.skipPrefix("Adobe", 6))
    ThrowTPE("Not Adobe Private data");

  if (!bs.skipPrefix("MakN", 4))
    ThrowTPE("Not Makernote");

  bs.setByteOrder(Endianness::big);
  uint32 makerNoteSize = bs.getU32();
  if (makerNoteSize != bs.getRemainSize())
    ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt");

  bs.setByteOrder(getTiffByteOrder(bs, 0, "DNG makernote"));
  bs.skipBytes(2);

  uint32 makerNoteOffset = bs.getU32();
  makerNoteSize -= 6; // update size of orinial maker note, we skipped 2+4 bytes

  // Update the underlying buffer of t, such that the maker note data starts at its original offset
  bs.rebase(makerNoteOffset, makerNoteSize);

  return parseMakerNote(ifds, t);
}

/* This will attempt to parse makernotes and return it as an IFD */
TiffRootIFDOwner TiffIFD::parseMakerNote(NORangesSet<Buffer>* ifds,
                                         TiffEntry* t) {
  assert(ifds);

  // go up the IFD tree and try to find the MAKE entry on each level.
  // we can not go all the way to the top first because this partial tree
  // is not yet added to the TiffRootIFD.
  TiffIFD* p = this;
  TiffEntry* makeEntry;
  do {
    makeEntry = p->getEntryRecursive(MAKE);
    p = p->parent;
  } while (!makeEntry && p);
  string make = makeEntry != nullptr ? trimSpaces(makeEntry->getString()) : "";

  ByteStream bs = t->getData();

  // helper function for easy setup of ByteStream buffer for the different maker note types
  // 'rebase' means position 0 of new stream equals current position
  // 'newPosition' is the position where the IFD starts
  // 'byteOrderOffset' is the position wher the 2 magic bytes (II/MM) may be found
  // 'context' is a string providing error information in case the byte order parsing should fail
  auto setup = [&bs](bool rebase, uint32 newPosition,
                     uint32 byteOrderOffset = 0,
                     const char *context = nullptr) {
    if (rebase)
      bs = bs.getSubStream(bs.getPosition(), bs.getRemainSize());
    if (context)
      bs.setByteOrder(getTiffByteOrder(bs, byteOrderOffset, context));
    bs.skipBytes(newPosition);
  };

  if (bs.hasPrefix("AOC\0", 4)) {
    setup(false, 6, 4, "Pentax makernote");
  } else if (bs.hasPrefix("PENTAX", 6)) {
    setup(true, 10, 8, "Pentax makernote");
  } else if (bs.hasPrefix("FUJIFILM\x0c\x00\x00\x00", 12)) {
    bs.setByteOrder(Endianness::little);
    setup(true, 12);
  } else if (bs.hasPrefix("Nikon\x00\x02", 7)) {
    // this is Nikon type 3 maker note format
    // TODO: implement Nikon type 1 maker note format
    // see http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html
    bs.skipBytes(10);
    setup(true, 8, 0, "Nikon makernote");
  } else if (bs.hasPrefix("OLYMPUS", 7)) { // new Olympus
    setup(true, 12);
  } else if (bs.hasPrefix("OLYMP", 5)) {   // old Olympus
    setup(true, 8);
  } else if (bs.hasPrefix("EPSON", 5)) {
    setup(false, 8);
  } else if (bs.hasPatternAt("Exif", 4, 6)) {
    // TODO: for none of the rawsamples.ch files from Panasonic is this true, instead their MakerNote start with "Panasonic"
    // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
    // This TIFF is 0 offset based
    setup(false, 20, 12, "Panosonic makernote");
  } else if (make == "SAMSUNG") {
    // Samsung has no identification in its MakerNote but starts with the IFD right away
    setup(true, 0);
  } else {
    // cerr << "default MakerNote from " << make << endl; // Canon, Nikon (type 2), Sony, Minolta, Ricoh, Leica, Hasselblad, etc.

    // At least one MAKE has not been handled explicitly and starts its MakerNote with an endian prefix: Kodak
    if (bs.skipPrefix("II", 2)) {
      bs.setByteOrder(Endianness::little);
    } else if (bs.skipPrefix("MM", 2)) {
      bs.setByteOrder(Endianness::big);
    }
  }

  // Attempt to parse the rest as an IFD
  return std::make_unique<TiffRootIFD>(this, ifds, bs, bs.getPosition());
}

std::vector<const TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) const {
  vector<const TiffIFD*> matchingIFDs;
  if (entries.find(tag) != entries.end()) {
    matchingIFDs.push_back(this);
  }
  for (auto& i : subIFDs) {
    vector<const TiffIFD*> t = i->getIFDsWithTag(tag);
    matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
  }
  return matchingIFDs;
}

const TiffIFD* TiffIFD::getIFDWithTag(TiffTag tag, uint32 index) const
{
  auto ifds = getIFDsWithTag(tag);
  if (index >= ifds.size())
    ThrowTPE("failed to find %u ifs with tag 0x%04x", index + 1, tag);
  return ifds[index];
}

TiffEntry* __attribute__((pure)) TiffIFD::getEntryRecursive(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i != entries.end()) {
    return i->second.get();
  }
  for (auto &j : subIFDs) {
    TiffEntry *entry = j->getEntryRecursive(tag);
    if (entry)
      return entry;
  }
  return nullptr;
}

void TiffIFD::checkOverflow() {
  TiffIFD* p = this;
  int i = 0;
  while ((p = p->parent) != nullptr) {
    i++;
    if (i > 5)
      ThrowTPE("TiffIFD cascading overflow.");
  }
}

void TiffIFD::add(TiffIFDOwner subIFD) {
  checkOverflow();
  if (subIFDs.size() > 100)
    ThrowTPE("TIFF file has too many SubIFDs, probably broken");
  subIFD->parent = this;
  subIFDs.push_back(move(subIFD));
}

void TiffIFD::add(TiffEntryOwner entry) {
  entry->parent = this;
  entries[entry->tag] = move(entry);
}

TiffEntry* TiffIFD::getEntry(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i == entries.end())
    ThrowTPE("Entry 0x%x not found.", tag);
  return i->second.get();
}

TiffID TiffRootIFD::getID() const
{
  TiffID id;
  auto makeE = getEntryRecursive(MAKE);
  auto modelE = getEntryRecursive(MODEL);

  if (!makeE)
    ThrowTPE("Failed to find MAKE entry.");
  if (!modelE)
    ThrowTPE("Failed to find MODEL entry.");

  id.make = trimSpaces(makeE->getString());
  id.model = trimSpaces(modelE->getString());

  return id;
}

} // namespace rawspeed
<|endoftext|>


<commit_before><commit_msg>fixed call to p objects<commit_after><|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: datasource.hpp 43 2005-04-22 18:52:47Z pavlenko $

#ifndef DATASOURCE_HPP
#define DATASOURCE_HPP
// stl
#include <map>
#include <string>
// boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/params.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>

namespace mapnik {
    typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

    struct MAPNIK_DECL Featureset
    {
        virtual feature_ptr next()=0;
        virtual ~Featureset() {};
    };

    typedef MAPNIK_DECL boost::shared_ptr<Featureset> featureset_ptr;

    class MAPNIK_DECL datasource_exception : public std::exception
    {
    private:
        const std::string message_;
    public:
        datasource_exception(const std::string& message=std::string())
            :message_(message) {}

        ~datasource_exception() throw() {}
        virtual const char* what() const throw()
        {
            return message_.c_str();
        }
    };

    class MAPNIK_DECL datasource : private boost::noncopyable
    {
        parameters params_;
    public:
        enum {
            Vector,
            Raster
        };

        datasource (parameters const& params)
            : params_(params) {}

        parameters const& params() const
        {
            return params_;
        }

        virtual int type() const=0;
        virtual featureset_ptr features(const query& q) const=0;
        virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
        virtual Envelope<double> envelope() const=0;
        virtual layer_descriptor get_descriptor() const=0;
        virtual ~datasource() {};
    };

    typedef std::string datasource_name();
    typedef datasource* create_ds(const parameters& params);
    typedef void destroy_ds(datasource *ds);

    class datasource_deleter
    {
    public:
        void operator() (datasource* ds)
        {
            delete ds;
        }
    };

    typedef boost::shared_ptr<datasource> datasource_ptr;

    #define DATASOURCE_PLUGIN(classname)                              \
        extern "C" MAPNIK_DECL std::string datasource_name()            \
        {                                                               \
            return classname::name();                                   \
        }                                                               \
        extern "C"  MAPNIK_DECL datasource* create(const parameters &params) \
        {                                                               \
            return new classname(params);                               \
        }                                                               \
        extern "C" MAPNIK_DECL void destroy(datasource *ds)             \
        {                                                               \
            delete ds;                                                  \
        }                                                               \
        //
}

#endif //DATASOURCE_HPP
<commit_msg>make params_ accessible from derived classes<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: datasource.hpp 43 2005-04-22 18:52:47Z pavlenko $

#ifndef DATASOURCE_HPP
#define DATASOURCE_HPP
// stl
#include <map>
#include <string>
// boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/params.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>

namespace mapnik {
    typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

    struct MAPNIK_DECL Featureset
    {
        virtual feature_ptr next()=0;
        virtual ~Featureset() {};
    };

    typedef MAPNIK_DECL boost::shared_ptr<Featureset> featureset_ptr;

    class MAPNIK_DECL datasource_exception : public std::exception
    {
    private:
        const std::string message_;
    public:
        datasource_exception(const std::string& message=std::string())
            :message_(message) {}

        ~datasource_exception() throw() {}
        virtual const char* what() const throw()
        {
            return message_.c_str();
        }
    };

    class MAPNIK_DECL datasource : private boost::noncopyable
    {
    public:
        enum {
            Vector,
            Raster
        };

        datasource (parameters const& params)
            : params_(params) {}

        parameters const& params() const
        {
            return params_;
        }

        virtual int type() const=0;
        virtual featureset_ptr features(const query& q) const=0;
        virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
        virtual Envelope<double> envelope() const=0;
        virtual layer_descriptor get_descriptor() const=0;
        virtual ~datasource() {};
    protected:
        parameters params_;
    };

    typedef std::string datasource_name();
    typedef datasource* create_ds(const parameters& params);
    typedef void destroy_ds(datasource *ds);

    class datasource_deleter
    {
    public:
        void operator() (datasource* ds)
        {
            delete ds;
        }
    };

    typedef boost::shared_ptr<datasource> datasource_ptr;

    #define DATASOURCE_PLUGIN(classname)                              \
        extern "C" MAPNIK_DECL std::string datasource_name()            \
        {                                                               \
            return classname::name();                                   \
        }                                                               \
        extern "C"  MAPNIK_DECL datasource* create(const parameters &params) \
        {                                                               \
            return new classname(params);                               \
        }                                                               \
        extern "C" MAPNIK_DECL void destroy(datasource *ds)             \
        {                                                               \
            delete ds;                                                  \
        }                                                               \
        //
}

#endif //DATASOURCE_HPP
<|endoftext|>