<commit_before>// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
// cmemlink.cc
//
// See cmemlink.h for documentation.
//

#include "cmemlink.h"
#include "ofstream.h"
#include "strmsize.h"
#include "ualgo.h"

namespace ustl {

/// \brief Attaches the object to pointer \p p of size \p n.
///
/// If \p p is NULL and \p n is non-zero, bad_alloc is thrown and current
/// state remains unchanged.
///
void cmemlink::link (const void* p, size_type n)
{
    if (!p && n)
	throw bad_alloc (n);
    unlink();
    relink (p, n);
}

/// Writes the object to stream \p os
void cmemlink::write (ostream& os) const
{
    const written_size_type sz (size());
    assert (sz == size() && "No support for writing memblocks larger than 4G");
    os << sz;
    os.write (cdata(), sz);
    os.align (alignof (sz));
}

/// Writes the object to stream \p os
void cmemlink::text_write (ostringstream& os) const
{
    os.write (begin(), readable_size());
}

/// Returns the number of bytes required to write this object to a stream.
cmemlink::size_type cmemlink::stream_size (void) const
{
    const written_size_type sz (size());
    return (Align (stream_size_of (sz) + sz, alignof(sz)));
}

/// Writes the data to file \p "filename".
void cmemlink::write_file (const char* filename, int mode) const
{
    fstream f;
    f.exceptions (fstream::allbadbits);
    f.open (filename, fstream::out | fstream::trunc, mode);
    f.write (cdata(), readable_size());
    f.close();
}

/// swaps the contents with \p l
void cmemlink::swap (cmemlink& l)
{
#if CPU_HAS_MMX
    asm (
	"movq %0, %%mm0\n\t"
	"movq %2, %%mm1\n\t"
	"movq %%mm0, %2\n\t"
	"movq %%mm1, %0\n\t"
	: "=m"(m_Data), "=m"(m_Size), "=m"(l.m_Data), "=m"(l.m_Size)
	:
	: "mm0", "mm1", "st", "st(1)");
    simd::reset_mmx();
#else
    ::ustl::swap (m_Data, l.m_Data);
    ::ustl::swap (m_Size, l.m_Size);
#endif
}

/// Compares to memory block pointed by l. Size is compared first.
bool cmemlink::operator== (const cmemlink& l) const
{
    return (l.m_Size == m_Size &&
	    (l.m_Data == m_Data || 0 == memcmp (l.m_Data, m_Data, m_Size)));
}

} // namespace ustl

<commit_msg>Fixed swap to use SSE instead of MMX on x86_64<commit_after>// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
// cmemlink.cc
//
// See cmemlink.h for documentation.
//

#include "cmemlink.h"
#include "ofstream.h"
#include "strmsize.h"
#include "ualgo.h"

namespace ustl {

/// \brief Attaches the object to pointer \p p of size \p n.
///
/// If \p p is NULL and \p n is non-zero, bad_alloc is thrown and current
/// state remains unchanged.
///
void cmemlink::link (const void* p, size_type n)
{
    if (!p && n)
	throw bad_alloc (n);
    unlink();
    relink (p, n);
}

/// Writes the object to stream \p os
void cmemlink::write (ostream& os) const
{
    const written_size_type sz (size());
    assert (sz == size() && "No support for writing memblocks larger than 4G");
    os << sz;
    os.write (cdata(), sz);
    os.align (alignof (sz));
}

/// Writes the object to stream \p os
void cmemlink::text_write (ostringstream& os) const
{
    os.write (begin(), readable_size());
}

/// Returns the number of bytes required to write this object to a stream.
cmemlink::size_type cmemlink::stream_size (void) const
{
    const written_size_type sz (size());
    return (Align (stream_size_of (sz) + sz, alignof(sz)));
}

/// Writes the data to file \p "filename".
void cmemlink::write_file (const char* filename, int mode) const
{
    fstream f;
    f.exceptions (fstream::allbadbits);
    f.open (filename, fstream::out | fstream::trunc, mode);
    f.write (cdata(), readable_size());
    f.close();
}

/// swaps the contents with \p l
void cmemlink::swap (cmemlink& l)
{
#if CPU_HAS_MMX && SIZE_OF_POINTER == 4
    asm (
	"movq %0, %%mm0\n\t"
	"movq %2, %%mm1\n\t"
	"movq %%mm0, %2\n\t"
	"movq %%mm1, %0\n\t"
	: "=m"(m_Data), "=m"(m_Size), "=m"(l.m_Data), "=m"(l.m_Size)
	:
	: "mm0", "mm1", "st", "st(1)");
    simd::reset_mmx();
#elif CPU_HAS_SSE && SIZE_OF_POINTER == 8
    asm (
	"movups %0, %%xmm0\n\t"
	"movups %2, %%xmm1\n\t"
	"movups %%xmm0, %2\n\t"
	"movups %%xmm1, %0\n\t"
	: "=m"(m_Data), "=m"(m_Size), "=m"(l.m_Data), "=m"(l.m_Size)
	:
	: "xmm0", "xmm1");
#else
    ::ustl::swap (m_Data, l.m_Data);
    ::ustl::swap (m_Size, l.m_Size);
#endif
}

/// Compares to memory block pointed by l. Size is compared first.
bool cmemlink::operator== (const cmemlink& l) const
{
    return (l.m_Size == m_Size &&
	    (l.m_Data == m_Data || 0 == memcmp (l.m_Data, m_Data, m_Size)));
}

} // namespace ustl

<|endoftext|>


<commit_before>/*
   Factor integers using a combination of trial division by small primes,
   and Pollard's Rho algorithm
*/
#include <botan/botan.h>
#include <botan/reducer.h>
#include <botan/numthry.h>
using namespace Botan;

#include <algorithm>
#include <iostream>

// Pollard's Rho algorithm, as described in the MIT algorithms book

// We use (x^2+x) mod n instead of (x*2-1) mod n as the random function,
// it _seems_ to lead to faster factorization for the values I tried.

BigInt rho(const BigInt& n)
   {
   BigInt x = random_integer(0, n-1);
   BigInt y = x;
   BigInt d = 0;

   Modular_Reducer mod_n(n);

   u32bit i = 1, k = 2;
   while(true)
      {
      i++;

      x = mod_n.multiply((x + 1), x);

      d = gcd(y - x, n);
      if(d != 1 && d != n)
         return d;

      if(i == 65536) // bail
         break;

      if(i == k)
         {
         y = x;
         k = 2*k;
         }
      }
   return 0;
   }

// Remove (and return) any small (< 2^16) factors
std::vector<BigInt> remove_small_factors(BigInt& n)
   {
   std::vector<BigInt> factors;

   while(n.is_even())
      {
      factors.push_back(2);
      n /= 2;
      }

   for(u32bit j = 0; j != PRIME_TABLE_SIZE; j++)
      {
      if(n < PRIMES[j])
         break;

      BigInt x = gcd(n, PRIMES[j]);

      if(x != 1)
         {
         n /= x;

         u32bit occurs = 0;
         while(x != 1)
            {
            x /= PRIMES[j];
            occurs++;
            }

         for(u32bit k = 0; k != occurs; k++)
            factors.push_back(PRIMES[j]);
         }
      }

   return factors;
   }

std::vector<BigInt> factorize(const BigInt& n_in)
   {
   BigInt n = n_in;
   std::vector<BigInt> factors = remove_small_factors(n);

   while(n != 1)
      {
      if(is_prime(n))
         {
         factors.push_back(n);
         break;
         }

      BigInt a_factor = 0;
      while(a_factor == 0)
         a_factor = rho(n);

      std::vector<BigInt> rho_factored = factorize(a_factor);
      for(u32bit j = 0; j != rho_factored.size(); j++)
         factors.push_back(rho_factored[j]);

      n /= a_factor;
      }
   return factors;
   }

int main(int argc, char* argv[])
   {
   if(argc != 2)
      {
      std::cerr << "Usage: " << argv[0] << " integer\n";
      return 1;
      }

   try
      {
      LibraryInitializer init;

      BigInt n(argv[1]);

      std::vector<BigInt> factors = factorize(n);
      std::sort(factors.begin(), factors.end());

      std::cout << n << ": ";
      for(u32bit j = 0; j != factors.size(); j++)
         std::cout << factors[j] << " ";
      std::cout << "\n";
      }
   catch(std::exception& e)
      {
      std::cout << e.what() << std::endl;
      return 1;
      }
   return 0;
   }
<commit_msg>Don't bail out of the rho computation until 2^32 tries, since the cycle size is based on the square root of the prime factors, bailing after 2^16 would mean we would be unlikely to find any factors larger than 32 bits.<commit_after>/*
   Factor integers using a combination of trial division by small primes,
   and Pollard's Rho algorithm
*/
#include <botan/botan.h>
#include <botan/reducer.h>
#include <botan/numthry.h>
using namespace Botan;

#include <algorithm>
#include <iostream>

// Pollard's Rho algorithm, as described in the MIT algorithms book

// We use (x^2+x) mod n instead of (x*2-1) mod n as the random function,
// it _seems_ to lead to faster factorization for the values I tried.

BigInt rho(const BigInt& n)
   {
   BigInt x = random_integer(0, n-1);
   BigInt y = x;
   BigInt d = 0;

   Modular_Reducer mod_n(n);

   u32bit i = 1, k = 2;
   while(true)
      {
      i++;

      if(i == 0) // overflow, bail out
         break;

      x = mod_n.multiply((x + 1), x);

      d = gcd(y - x, n);
      if(d != 1 && d != n)
         return d;

      if(i == k)
         {
         y = x;
         k = 2*k;
         }
      }
   return 0;
   }

// Remove (and return) any small (< 2^16) factors
std::vector<BigInt> remove_small_factors(BigInt& n)
   {
   std::vector<BigInt> factors;

   while(n.is_even())
      {
      factors.push_back(2);
      n /= 2;
      }

   for(u32bit j = 0; j != PRIME_TABLE_SIZE; j++)
      {
      if(n < PRIMES[j])
         break;

      BigInt x = gcd(n, PRIMES[j]);

      if(x != 1)
         {
         n /= x;

         u32bit occurs = 0;
         while(x != 1)
            {
            x /= PRIMES[j];
            occurs++;
            }

         for(u32bit k = 0; k != occurs; k++)
            factors.push_back(PRIMES[j]);
         }
      }

   return factors;
   }

std::vector<BigInt> factorize(const BigInt& n_in)
   {
   BigInt n = n_in;
   std::vector<BigInt> factors = remove_small_factors(n);

   while(n != 1)
      {
      if(is_prime(n))
         {
         factors.push_back(n);
         break;
         }

      BigInt a_factor = 0;
      while(a_factor == 0)
         a_factor = rho(n);

      std::vector<BigInt> rho_factored = factorize(a_factor);
      for(u32bit j = 0; j != rho_factored.size(); j++)
         factors.push_back(rho_factored[j]);

      n /= a_factor;
      }
   return factors;
   }

int main(int argc, char* argv[])
   {
   if(argc != 2)
      {
      std::cerr << "Usage: " << argv[0] << " integer\n";
      return 1;
      }

   try
      {
      LibraryInitializer init;

      BigInt n(argv[1]);

      std::vector<BigInt> factors = factorize(n);
      std::sort(factors.begin(), factors.end());

      std::cout << n << ": ";
      for(u32bit j = 0; j != factors.size(); j++)
         std::cout << factors[j] << " ";
      std::cout << "\n";
      }
   catch(std::exception& e)
      {
      std::cout << e.what() << std::endl;
      return 1;
      }
   return 0;
   }
<|endoftext|>


<commit_before>#include <stdint.h>
#include <stddef.h>
#include <atomic>

namespace bounded {
template<uint32_t size, class T>
class ProducerConsumerQueue {
  public:
    // size must be >= 2.
    //
    // Also, note that the number of usable slots in the queue at any
    // given time is actually (size-1), so if you start with an empty queue,
    // PushBack will fail after size-1 insertions.
    ProducerConsumerQueue() : readIndex_(0), writeIndex_(0) {
      memset(&records_, 0, sizeof(records_[0]) * size);
    }

    // Returns false if the queue is full, cannot insert nullptr
    bool PushBack(T* item) {
      auto const currentWrite = writeIndex_.load(std::memory_order_relaxed);
      auto nextRecord = currentWrite + 1;
      if (nextRecord == size) {
        nextRecord = 0;
      }

      if (nextRecord != readIndex_.load(std::memory_order_acquire)) {
        records_[currentWrite] = item;
        writeIndex_.store(nextRecord, std::memory_order_release);
        return true;
      }

      // queue is full
      return false;
    }

    // Returns nullptr if the queue is empty.
    T* PopFront() {
      auto const currentRead = readIndex_.load(std::memory_order_relaxed);
      if (currentRead == writeIndex_.load(std::memory_order_acquire)) {
        // queue is empty
        return nullptr;
      }

      auto nextRecord = currentRead + 1;
      if (nextRecord == size) {
        nextRecord = 0;
      }
      T* ret = records_[currentRead];
      readIndex_.store(nextRecord, std::memory_order_release);
      return ret;
    }
  private:
    static const size_t kCacheLineLength = 128;
    typedef char padding[kCacheLineLength];
    padding padding1_;
    T* records_[size];
    padding padding2_;
    std::atomic<unsigned int> readIndex_;
    padding padding3_;
    std::atomic<unsigned int> writeIndex_;
    padding padding4_;
};

}
<commit_msg>added string.h<commit_after>#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <atomic>

namespace bounded {
template<uint32_t size, class T>
class ProducerConsumerQueue {
  public:
    // size must be >= 2.
    //
    // Also, note that the number of usable slots in the queue at any
    // given time is actually (size-1), so if you start with an empty queue,
    // PushBack will fail after size-1 insertions.
    ProducerConsumerQueue() : readIndex_(0), writeIndex_(0) {
      memset(&records_, 0, sizeof(records_[0]) * size);
    }

    // Returns false if the queue is full, cannot insert nullptr
    bool PushBack(T* item) {
      auto const currentWrite = writeIndex_.load(std::memory_order_relaxed);
      auto nextRecord = currentWrite + 1;
      if (nextRecord == size) {
        nextRecord = 0;
      }

      if (nextRecord != readIndex_.load(std::memory_order_acquire)) {
        records_[currentWrite] = item;
        writeIndex_.store(nextRecord, std::memory_order_release);
        return true;
      }

      // queue is full
      return false;
    }

    // Returns nullptr if the queue is empty.
    T* PopFront() {
      auto const currentRead = readIndex_.load(std::memory_order_relaxed);
      if (currentRead == writeIndex_.load(std::memory_order_acquire)) {
        // queue is empty
        return nullptr;
      }

      auto nextRecord = currentRead + 1;
      if (nextRecord == size) {
        nextRecord = 0;
      }
      T* ret = records_[currentRead];
      readIndex_.store(nextRecord, std::memory_order_release);
      return ret;
    }
  private:
    static const size_t kCacheLineLength = 128;
    typedef char padding[kCacheLineLength];
    padding padding1_;
    T* records_[size];
    padding padding2_;
    std::atomic<unsigned int> readIndex_;
    padding padding3_;
    std::atomic<unsigned int> writeIndex_;
    padding padding4_;
};

}
<|endoftext|>


<commit_before><commit_msg>syntactic sugar for HTML generation<commit_after><|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program 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.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "../Interface/Database.h"
#include "../Interface/Server.h"
#include "../Interface/File.h"
#include "../Interface/DatabaseCursor.h"
#include "database.h"
#include "../stringtools.h"
#include <iostream>
#include <fstream>
#include "../urbackupcommon/sha2/sha2.h"
#include "../urbackupcommon/os_functions.h"
#include <memory.h>
#include <memory>
#include "dao/ServerFilesDao.h"
#include "FileIndex.h"
#include "create_files_index.h"
#include "server_hash.h"
#include "serverinterface/helper.h"

const _u32 c_read_blocksize=4096;
const size_t draw_segments=30;
const size_t c_speed_size=15;
const size_t c_max_l_length=80;

void draw_progress(std::string curr_fn, _i64 curr_verified, _i64 verify_size)
{
	static _i64 last_progress_bytes=0;
	static int64 last_time=0;
	static size_t max_line_length=0;

	int64 passed_time=Server->getTimeMS()-last_time;
	if(passed_time>1000)
	{
		_i64 new_bytes=curr_verified-last_progress_bytes;

		float pc_done=(float)curr_verified/(float)verify_size;

		size_t segments=(size_t)(pc_done*draw_segments);

		std::string toc="\r[";
		for(size_t i=0;i<draw_segments;++i)
		{
			if(i<segments)
			{
				toc+="=";
			}
			else if(i==segments)
			{
				toc+=">";
			}
			else
			{
				toc+=" ";
			}
		}
		std::string speed_str=PrettyPrintSpeed((size_t)((new_bytes*1000)/passed_time));
		while(speed_str.size()<c_speed_size)
			speed_str+=" ";
		std::string pcdone=convert((int)(pc_done*100.f));
		if(pcdone.size()==1)
			pcdone=" "+pcdone;

		toc+="] "+pcdone+"% "+speed_str+" "+(curr_fn);

		if(toc.size()>=c_max_l_length)
		    toc=toc.substr(0, c_max_l_length);

		if(toc.size()>max_line_length)
		    max_line_length=toc.size();

		while(toc.size()<max_line_length)
		    toc+=" ";

		std::cout << toc;
		std::cout.flush();

		last_progress_bytes=curr_verified;
		last_time=Server->getTimeMS();
	}
}

bool verify_file(db_single_result &res, _i64 &curr_verified, _i64 verify_size, bool& missing)
{
	std::string fp=res["fullpath"];
	IFsFile *f=Server->openFile(os_file_prefix(fp), MODE_READ);
	if( f==NULL )
	{
		Server->Log("Error opening file \""+fp+"\"", LL_ERROR);
		missing = true;
		return false;
	}

	if(watoi64(res["filesize"])!=f->Size())
	{
		Server->Log("Filesize of \""+fp+"\" is wrong", LL_ERROR);
		return false;
	}

	std::string f_name=ExtractFileName(fp);

	FsExtentIterator extent_iterator(f, 32768);
	std::string calc_dig = BackupServerPrepareHash::hash_sha(f, &extent_iterator, true);
	curr_verified += f->Size();

	if(calc_dig.empty())
	{
		Server->Log("Could not read all bytes of file \""+fp+"\"", LL_ERROR);
		return false;
	}

	if(res["shahash"]!=calc_dig)
	{
		Server->Log("Hash of \""+fp+"\" is wrong", LL_ERROR);
		return false;
	}

	return true;
}

bool verify_hashes(std::string arg)
{
	IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);

	std::string working_dir=(Server->getServerWorkingDir());
	std::string v_output_fn=working_dir+os_file_sep()+"urbackup"+os_file_sep()+"verification_result.txt";
	std::fstream v_failure;
	v_failure.open(v_output_fn.c_str(), std::ios::out|std::ios::binary);
	if( !v_failure.is_open() )
		Server->Log("Could not open \""+v_output_fn+"\" for writing", LL_ERROR);
	else
		Server->Log("Writing verification results to \""+v_output_fn+"\"", LL_INFO);

	std::string clientname;
	std::string backupname;

	if(arg!="true")
	{
		if(arg.find("/")==std::string::npos)
		{
			clientname=arg;
		}
		else
		{
			clientname=getuntil("/", arg);
			backupname=getafter("/", arg);

		}
	}

	bool delete_failed = Server->getServerParameter("delete_verify_failed")=="true";

	int cid=0;
	int backupid=0;
	std::string filter;

	IDatabase *files_db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);

	if(!clientname.empty())
	{
		if(clientname!="*")
		{
			IQuery *q=db->Prepare("SELECT id FROM clients WHERE name=?");
			q->Bind(clientname);
			db_results res=q->Read();
			if(!res.empty())
			{
				cid=watoi(res[0]["id"]);
			}
			else
			{
				Server->Log("Client \""+clientname+"\" not found", LL_ERROR);
				return false;
			}

			filter=" WHERE clientid="+convert(cid);
		}
		else
		{
			filter+=" WHERE 1=1";
		}

		if(!backupname.empty())
		{
			std::string backupid_filter;
			std::string temp_create_query;
			if(backupname=="last")
			{
				if(clientname!="*")
				{
					IQuery* q=db->Prepare("SELECT id,path FROM backups WHERE clientid=? AND complete=1 ORDER BY backuptime DESC LIMIT 1");
					q->Bind(cid);
					db_results res=q->Read();
					if(!res.empty())
					{
						backupid_filter="= "+res[0]["id"];
						Server->Log("Last backup: "+res[0]["path"], LL_INFO);
					}
					else
					{
						Server->Log("Last backup not found", LL_ERROR);
						return false;
					}
				}
				else
				{
					backupid_filter = " IN (SELECT id FROM backups)";
					temp_create_query = "SELECT id FROM backups b WHERE NOT EXISTS (SELECT id FROM backups c WHERE complete=1 AND c.backuptime > b.backuptime AND b.clientid=c.clientid)";
				}

			}
			else if(backupname=="*")
			{
				backupid_filter=" IN (SELECT id FROM backups)";
				temp_create_query = "SELECT id FROM backups WHERE clientid=" + convert(cid);
			}
			else
			{
				IQuery* q=db->Prepare("SELECT id FROM backups WHERE path=? AND clientid=?");
				q->Bind(backupname);
				q->Bind(cid);
				db_results res=q->Read();
				if(!res.empty())
				{
					backupid_filter="= "+res[0]["id"];
				}
				else
				{
					Server->Log("Backup \""+backupname+"\" not found", LL_ERROR);

					return false;
				}
			}

			if(backupname!="*" || clientname!="*")
			{
				filter+=" AND backupid "+backupid_filter;
			}

			if (!temp_create_query.empty())
			{
				files_db->Write("CREATE TEMPORARY TABLE backups (id INTEGER PRIMARY KEY)");

				IQuery* q_insert = files_db->Prepare("INSERT INTO backups (id) VALUES (?)", false);
				IQuery* q_backup_ids = db->Prepare(temp_create_query, false);
				IDatabaseCursor* cur = q_backup_ids->Cursor();

				db_single_result res;
				while (cur->next(res))
				{
					q_insert->Bind(res["id"]);
					q_insert->Write();
					q_insert->Reset();
				}

				db->destroyQuery(q_backup_ids);
				files_db->destroyQuery(q_insert);
			}
		}
	}

	std::cout << "Calculating filesize..." << std::endl;
	IQuery *q_num_files=db->Prepare("SELECT SUM(filesize) AS c FROM files"+filter);
	db_results res=q_num_files->Read();
	if(res.empty())
	{
		Server->Log("Error during filesize calculation.", LL_ERROR);
		return false;
	}

	_i64 verify_size=watoi64(res[0]["c"]);
	_i64 curr_verified=0;

	std::cout << "To be verified: " << PrettyPrintBytes(verify_size) << " of files" << std::endl;

	_i64 crowid=0;

	IQuery *q_get_files=db->Prepare("SELECT id, fullpath, shahash, filesize FROM files"+filter, false);

	bool is_okay=true;

	IDatabaseCursor* cursor = q_get_files->Cursor();

	std::vector<int64> todelete;
	std::vector<int64> missing_files;

	db_single_result res_single;
	while(cursor->next(res_single))
	{
		bool is_missing=false;
		if(! verify_file( res_single, curr_verified, verify_size, is_missing) )
		{
			if(!is_missing)
			{
				v_failure << "Verification of \"" << (res_single["fullpath"]) << "\" failed\r\n";
				is_okay=false;

				if(delete_failed)
				{
					todelete.push_back(watoi64(res_single["id"]));
				}
			}
			else
			{
				missing_files.push_back(watoi64(res_single["id"]));
			}
		}
	}

	if(v_failure.is_open() && is_okay)
	{
		v_failure.close();
		Server->deleteFile(v_output_fn);
	}

	db->destroyQuery(q_get_files);

	IQuery* q_get_file = db->Prepare("SELECT id, fullpath, shahash, filesize FROM files WHERE id=?");

	std::cout << missing_files.size() << " could not be opened during verification. Checking now if they have been deleted from the database..." << std::endl;

	for(size_t i=0;i<missing_files.size();++i)
	{
		q_get_file->Bind(missing_files[i]);
		db_results res = q_get_file->Read();
		q_get_file->Reset();

		if(!res.empty())
		{
			bool is_missing=false;
			db_single_result& res_single = res[0];
			if(!verify_file(res_single, curr_verified, verify_size, is_missing))
			{
				v_failure << "Verification of file \"" << (res_single["fullpath"]) << "\" failed (during rechecking previously missing files)\r\n";
				is_okay=false;

				if(delete_failed)
				{
					todelete.push_back(watoi64(res_single["id"]));
				}
			}
		}
	}

	std::cout << std::endl;

	if(delete_failed)
	{
		std::cout << "Deleting " << todelete.size() << " file entries with failed verification from database..." << std::endl;

		SStartupStatus status;
		if(!create_files_index(status))
		{
			std::cout << "Error opening file index -1" << std::endl;
		}
		else
		{
			ServerFilesDao backupdao(db);
			std::auto_ptr<FileIndex> fileindex(create_lmdb_files_index());

			if(fileindex.get()==NULL)
			{
				std::cout << "Error opening file index -2" << std::endl;
			}
			else
			{

				for(size_t i=0;i<todelete.size();++i)
				{
					BackupServerHash::deleteFileSQL(backupdao, *fileindex, todelete[i]);
				}

				std::cout << "done." << std::endl;
			}
		}
	}

	return is_okay;
}<commit_msg>Fixed verification via command line<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program 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.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "../Interface/Database.h"
#include "../Interface/Server.h"
#include "../Interface/File.h"
#include "../Interface/DatabaseCursor.h"
#include "database.h"
#include "../stringtools.h"
#include <iostream>
#include <fstream>
#include "../urbackupcommon/sha2/sha2.h"
#include "../urbackupcommon/os_functions.h"
#include <memory.h>
#include <memory>
#include "dao/ServerFilesDao.h"
#include "FileIndex.h"
#include "create_files_index.h"
#include "server_hash.h"
#include "serverinterface/helper.h"

const _u32 c_read_blocksize=4096;
const size_t draw_segments=30;
const size_t c_speed_size=15;
const size_t c_max_l_length=80;

void draw_progress(std::string curr_fn, _i64 curr_verified, _i64 verify_size)
{
	static _i64 last_progress_bytes=0;
	static int64 last_time=0;
	static size_t max_line_length=0;

	int64 passed_time=Server->getTimeMS()-last_time;
	if(passed_time>1000)
	{
		_i64 new_bytes=curr_verified-last_progress_bytes;

		float pc_done=(float)curr_verified/(float)verify_size;

		size_t segments=(size_t)(pc_done*draw_segments);

		std::string toc="\r[";
		for(size_t i=0;i<draw_segments;++i)
		{
			if(i<segments)
			{
				toc+="=";
			}
			else if(i==segments)
			{
				toc+=">";
			}
			else
			{
				toc+=" ";
			}
		}
		std::string speed_str=PrettyPrintSpeed((size_t)((new_bytes*1000)/passed_time));
		while(speed_str.size()<c_speed_size)
			speed_str+=" ";
		std::string pcdone=convert((int)(pc_done*100.f));
		if(pcdone.size()==1)
			pcdone=" "+pcdone;

		toc+="] "+pcdone+"% "+speed_str+" "+(curr_fn);

		if(toc.size()>=c_max_l_length)
		    toc=toc.substr(0, c_max_l_length);

		if(toc.size()>max_line_length)
		    max_line_length=toc.size();

		while(toc.size()<max_line_length)
		    toc+=" ";

		std::cout << toc;
		std::cout.flush();

		last_progress_bytes=curr_verified;
		last_time=Server->getTimeMS();
	}
}

bool verify_file(db_single_result &res, _i64 &curr_verified, _i64 verify_size, bool& missing)
{
	std::string fp=res["fullpath"];
	IFsFile *f=Server->openFile(os_file_prefix(fp), MODE_READ);
	if( f==NULL )
	{
		Server->Log("Error opening file \""+fp+"\"", LL_ERROR);
		missing = true;
		return false;
	}

	if(watoi64(res["filesize"])!=f->Size())
	{
		Server->Log("Filesize of \""+fp+"\" is wrong", LL_ERROR);
		return false;
	}

	std::string f_name=ExtractFileName(fp);

	FsExtentIterator extent_iterator(f, 32768);
	std::string calc_dig = BackupServerPrepareHash::hash_sha(f, &extent_iterator, true);
	curr_verified += f->Size();

	if(calc_dig.empty())
	{
		Server->Log("Could not read all bytes of file \""+fp+"\"", LL_ERROR);
		return false;
	}

	if(res["shahash"]!=calc_dig)
	{
		Server->Log("Hash of \""+fp+"\" is wrong", LL_ERROR);
		return false;
	}

	return true;
}

bool verify_hashes(std::string arg)
{
	IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);

	std::string working_dir=(Server->getServerWorkingDir());
	std::string v_output_fn=working_dir+os_file_sep()+"urbackup"+os_file_sep()+"verification_result.txt";
	std::fstream v_failure;
	v_failure.open(v_output_fn.c_str(), std::ios::out|std::ios::binary);
	if( !v_failure.is_open() )
		Server->Log("Could not open \""+v_output_fn+"\" for writing", LL_ERROR);
	else
		Server->Log("Writing verification results to \""+v_output_fn+"\"", LL_INFO);

	std::string clientname;
	std::string backupname;

	if(arg!="true")
	{
		if(arg.find("/")==std::string::npos)
		{
			clientname=arg;
		}
		else
		{
			clientname=getuntil("/", arg);
			backupname=getafter("/", arg);

		}
	}

	bool delete_failed = Server->getServerParameter("delete_verify_failed")=="true";

	int cid=0;
	int backupid=0;
	std::string filter;

	IDatabase *files_db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);

	if(!clientname.empty())
	{
		if(clientname!="*")
		{
			IQuery *q=db->Prepare("SELECT id FROM clients WHERE name=?");
			q->Bind(clientname);
			db_results res=q->Read();
			if(!res.empty())
			{
				cid=watoi(res[0]["id"]);
			}
			else
			{
				Server->Log("Client \""+clientname+"\" not found", LL_ERROR);
				return false;
			}

			filter=" WHERE clientid="+convert(cid);
		}
		else
		{
			filter+=" WHERE 1=1";
		}

		if(!backupname.empty())
		{
			std::string backupid_filter;
			std::string temp_create_query;
			if(backupname=="last")
			{
				if(clientname!="*")
				{
					IQuery* q=db->Prepare("SELECT id,path FROM backups WHERE clientid=? AND complete=1 ORDER BY backuptime DESC LIMIT 1");
					q->Bind(cid);
					db_results res=q->Read();
					if(!res.empty())
					{
						backupid_filter="= "+res[0]["id"];
						Server->Log("Last backup: "+res[0]["path"], LL_INFO);
					}
					else
					{
						Server->Log("Last backup not found", LL_ERROR);
						return false;
					}
				}
				else
				{
					backupid_filter = " IN (SELECT id FROM backups)";
					temp_create_query = "SELECT id FROM backups b WHERE NOT EXISTS (SELECT id FROM backups c WHERE complete=1 AND c.backuptime > b.backuptime AND b.clientid=c.clientid)";
				}

			}
			else if(backupname=="*")
			{
				backupid_filter=" IN (SELECT id FROM backups)";
				temp_create_query = "SELECT id FROM backups WHERE clientid=" + convert(cid);
			}
			else
			{
				IQuery* q=db->Prepare("SELECT id FROM backups WHERE path=? AND clientid=?");
				q->Bind(backupname);
				q->Bind(cid);
				db_results res=q->Read();
				if(!res.empty())
				{
					backupid_filter="= "+res[0]["id"];
				}
				else
				{
					Server->Log("Backup \""+backupname+"\" not found", LL_ERROR);

					return false;
				}
			}

			if(backupname!="*" || clientname!="*")
			{
				filter+=" AND backupid "+backupid_filter;
			}

			if (!temp_create_query.empty())
			{
				files_db->Write("CREATE TEMPORARY TABLE backups (id INTEGER PRIMARY KEY)");

				IQuery* q_insert = files_db->Prepare("INSERT INTO backups (id) VALUES (?)", false);
				IQuery* q_backup_ids = db->Prepare(temp_create_query, false);
				IDatabaseCursor* cur = q_backup_ids->Cursor();

				db_single_result res;
				while (cur->next(res))
				{
					q_insert->Bind(res["id"]);
					q_insert->Write();
					q_insert->Reset();
				}

				db->destroyQuery(q_backup_ids);
				files_db->destroyQuery(q_insert);
			}
		}
	}

	std::cout << "Calculating filesize..." << std::endl;
	IQuery *q_num_files = files_db->Prepare("SELECT SUM(filesize) AS c FROM files"+filter);
	db_results res=q_num_files->Read();
	if(res.empty())
	{
		Server->Log("Error during filesize calculation.", LL_ERROR);
		return false;
	}

	_i64 verify_size=watoi64(res[0]["c"]);
	_i64 curr_verified=0;

	std::cout << "To be verified: " << PrettyPrintBytes(verify_size) << " of files" << std::endl;

	_i64 crowid=0;

	IQuery *q_get_files = files_db->Prepare("SELECT id, fullpath, shahash, filesize FROM files"+filter, false);

	bool is_okay=true;

	IDatabaseCursor* cursor = q_get_files->Cursor();

	std::vector<int64> todelete;
	std::vector<int64> missing_files;

	db_single_result res_single;
	while(cursor->next(res_single))
	{
		bool is_missing=false;
		if(! verify_file( res_single, curr_verified, verify_size, is_missing) )
		{
			if(!is_missing)
			{
				v_failure << "Verification of \"" << (res_single["fullpath"]) << "\" failed\r\n";
				is_okay=false;

				if(delete_failed)
				{
					todelete.push_back(watoi64(res_single["id"]));
				}
			}
			else
			{
				missing_files.push_back(watoi64(res_single["id"]));
			}
		}
	}

	if(v_failure.is_open() && is_okay)
	{
		v_failure.close();
		Server->deleteFile(v_output_fn);
	}

	files_db->destroyQuery(q_get_files);

	IQuery* q_get_file = files_db->Prepare("SELECT id, fullpath, shahash, filesize FROM files WHERE id=?");

	std::cout << missing_files.size() << " could not be opened during verification. Checking now if they have been deleted from the database..." << std::endl;

	for(size_t i=0;i<missing_files.size();++i)
	{
		q_get_file->Bind(missing_files[i]);
		db_results res = q_get_file->Read();
		q_get_file->Reset();

		if(!res.empty())
		{
			bool is_missing=false;
			db_single_result& res_single = res[0];
			if(!verify_file(res_single, curr_verified, verify_size, is_missing))
			{
				v_failure << "Verification of file \"" << (res_single["fullpath"]) << "\" failed (during rechecking previously missing files)\r\n";
				is_okay=false;

				if(delete_failed)
				{
					todelete.push_back(watoi64(res_single["id"]));
				}
			}
		}
	}

	std::cout << std::endl;

	if(delete_failed)
	{
		std::cout << "Deleting " << todelete.size() << " file entries with failed verification from database..." << std::endl;

		SStartupStatus status;
		if(!create_files_index(status))
		{
			std::cout << "Error opening file index -1" << std::endl;
		}
		else
		{
			ServerFilesDao backupdao(files_db);
			std::auto_ptr<FileIndex> fileindex(create_lmdb_files_index());

			if(fileindex.get()==NULL)
			{
				std::cout << "Error opening file index -2" << std::endl;
			}
			else
			{

				for(size_t i=0;i<todelete.size();++i)
				{
					BackupServerHash::deleteFileSQL(backupdao, *fileindex, todelete[i]);
				}

				std::cout << "done." << std::endl;
			}
		}
	}

	return is_okay;
}<|endoftext|>


<commit_before>/*
 * Tests for policy dependency resolution.
 *
 * Copyright (C) 2019 Michal Koutenský
 * Author: Michal Koutenský <koutak.m@gmail.com>
 *
 * This file is part of rlite.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301 USA
 */
#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <cassert>
#include <chrono>
#include <unistd.h>
#include <cmath>

#include "uipcp-container.h"
#include "uipcp-normal.hpp"

struct TestPolicyDeps : public rlite::UipcpRib {
    struct uipcp uipcp;
    std::function<std::unique_ptr<rlite::Component>(UipcpRib *)> builder =
        [](UipcpRib *) { return nullptr; };
    TestPolicyDeps(struct uipcp *_u) : rlite::UipcpRib(_u, nullptr) {}

    int init();
};

int
TestPolicyDeps::init()
{
    std::string test_policy;
    std::vector<std::pair<std::string, std::string>> dependencies;
    int ret;

    /* Single policy without dependencies */
    test_policy = "test-no-depends";
    ret = policy_register(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }

    /* Nonexisting dependency */
    test_policy = "test-false-depends";
    dependencies.emplace_back(rlite::UipcpRib::ResourceAllocPrefix,
                              test_policy);
    ret = policy_register(rlite::UipcpRib::EnrollmentPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();

    /* A chain of policies with linear dependencies */
    test_policy = "test-linear-depends";
    ret         = policy_register(rlite::AddrAllocator::Prefix, test_policy);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << std::endl;
        return -1;
    }
    dependencies.emplace_back(rlite::AddrAllocator::Prefix, test_policy);
    ret = policy_register(rlite::UipcpRib::ResourceAllocPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::ResourceAllocPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();
    dependencies.emplace_back(rlite::UipcpRib::ResourceAllocPrefix,
                              test_policy);
    ret = policy_register(rlite::UipcpRib::EnrollmentPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();

    /* A chain of policies with duplicate indirect dependencies */
    test_policy = "test-duplicate-indirect-depends";
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-second");
    ret = policy_register(rlite::AddrAllocator::Prefix, test_policy + "-first",
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-first" << std::endl;
        return -1;
    }
    dependencies.clear();
    ret =
        policy_register(rlite::AddrAllocator::Prefix, test_policy + "-second");
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-second" << std::endl;
        return -1;
    }
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-first");
    ret = policy_register(rlite::UipcpRib::ResourceAllocPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();

    /* Cyclical dependencies */
    test_policy = "test-cyclic-depends";
    std::vector<
        std::tuple<const std::string &, const std::string &,
                   std::function<std::unique_ptr<rlite::Component>(UipcpRib *)>,
                   std::vector<std::string>,
                   std::vector<std::pair<std::string, rlite::PolicyParam>>,
                   std::vector<std::pair<std::string, std::string>>>>
        policies;

    using PolicyTuple =
        std::tuple<const std::string &, const std::string &,
                   std::function<std::unique_ptr<rlite::Component>(UipcpRib *)>,
                   std::vector<std::string>,
                   std::vector<std::pair<std::string, rlite::PolicyParam>>,
                   std::vector<std::pair<std::string, std::string>>>;

    policies.push_back(PolicyTuple(rlite::UipcpRib::EnrollmentPrefix,
                                   test_policy, builder, {}, {}, {}));
    policies.push_back(PolicyTuple(rlite::UipcpRib::ResourceAllocPrefix,
                                   test_policy, builder, {}, {}, {}));
    policies.push_back(PolicyTuple(rlite::AddrAllocator::Prefix, test_policy,
                                   builder, {}, {}, {}));
    ret = policy_register_group(policies);
    if (ret) {
        std::cout << "Failed to register policy group " << test_policy
                  << std::endl;
        return -1;
    }

    return 0;
}

int
main(int argc, char **argv)
{
    auto usage = []() {
        std::cout << "policy-deps-test -v be verbose\n"
                     "          -h show this help and exit\n";
    };
    int verbosity = 0;
    int opt;

    while ((opt = getopt(argc, argv, "hvn:")) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;

        case 'v':
            verbosity++;
            break;

        default:
            std::cout << "    Unrecognized option " << static_cast<char>(opt)
                      << std::endl;
            usage();
            return -1;
        }
    }

    struct uipcp uipcp;
    std::string name = "policy-deps-test";
    uipcp.name       = new char[name.length() + 1];
    name.copy(uipcp.name, name.length());
    uipcp.name[name.length()] = '\0';
    TestPolicyDeps test(&uipcp);
    if (test.init()) {
        std::cout << "Initialization of RIB for testing failed" << std::endl;
        return -1;
    }

    int ret = 0;
    std::string test_policy;

    /* Single policy without dependencies */
    test_policy = "test-no-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (!(ret == 0 &&
          test.policies[rlite::UipcpRib::EnrollmentPrefix] == test_policy)) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* Nonexisting dependency */
    test_policy = "test-false-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (ret == 0) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* A chain of policies with linear dependencies */
    test_policy = "test-linear-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (!(ret == 0 &&
          test.policies[rlite::UipcpRib::EnrollmentPrefix] == test_policy &&
          test.policies[rlite::UipcpRib::ResourceAllocPrefix] == test_policy &&
          test.policies[rlite::AddrAllocator::Prefix] == test_policy)) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* A chain of policies with duplicate direct dependencies */
    test_policy = "test-duplicate-direct-depends";
    std::vector<std::pair<std::string, std::string>> dependencies;
    test.policy_register(rlite::AddrAllocator::Prefix, test_policy + "-first");
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-first" << std::endl;
        return -1;
    }
    test.policy_register(rlite::AddrAllocator::Prefix, test_policy + "-second");
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-second" << std::endl;
        return -1;
    }
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-first");
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-second");
    ret = test.policy_register(rlite::UipcpRib::ResourceAllocPrefix,
                               test_policy, test.builder, {}, {}, dependencies);
    if (ret == 0) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }
    dependencies.clear();

    /* A chain of policies with duplicate indirect dependencies */
    test_policy = "test-duplicate-indirect-depends";
    ret = test.policy_mod(rlite::UipcpRib::ResourceAllocPrefix, test_policy);
    if (ret == 0) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* Cyclical dependencies */
    test_policy = "test-cyclic-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (!(ret == 0 &&
          test.policies[rlite::UipcpRib::EnrollmentPrefix] == test_policy &&
          test.policies[rlite::UipcpRib::ResourceAllocPrefix] == test_policy &&
          test.policies[rlite::AddrAllocator::Prefix] == test_policy)) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    return 0;
}
<commit_msg>uipcps: policy-deps-test: fix memory leak<commit_after>/*
 * Tests for policy dependency resolution.
 *
 * Copyright (C) 2019 Michal Koutenský
 * Author: Michal Koutenský <koutak.m@gmail.com>
 *
 * This file is part of rlite.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301 USA
 */
#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <cassert>
#include <chrono>
#include <unistd.h>
#include <cmath>

#include "uipcp-container.h"
#include "uipcp-normal.hpp"

struct TestPolicyDeps : public rlite::UipcpRib {
    struct uipcp uipcp;
    std::function<std::unique_ptr<rlite::Component>(UipcpRib *)> builder =
        [](UipcpRib *) { return nullptr; };
    TestPolicyDeps(struct uipcp *_u) : rlite::UipcpRib(_u, nullptr) {}

    int init();
};

int
TestPolicyDeps::init()
{
    std::string test_policy;
    std::vector<std::pair<std::string, std::string>> dependencies;
    int ret;

    /* Single policy without dependencies */
    test_policy = "test-no-depends";
    ret = policy_register(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }

    /* Nonexisting dependency */
    test_policy = "test-false-depends";
    dependencies.emplace_back(rlite::UipcpRib::ResourceAllocPrefix,
                              test_policy);
    ret = policy_register(rlite::UipcpRib::EnrollmentPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();

    /* A chain of policies with linear dependencies */
    test_policy = "test-linear-depends";
    ret         = policy_register(rlite::AddrAllocator::Prefix, test_policy);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << std::endl;
        return -1;
    }
    dependencies.emplace_back(rlite::AddrAllocator::Prefix, test_policy);
    ret = policy_register(rlite::UipcpRib::ResourceAllocPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::ResourceAllocPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();
    dependencies.emplace_back(rlite::UipcpRib::ResourceAllocPrefix,
                              test_policy);
    ret = policy_register(rlite::UipcpRib::EnrollmentPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();

    /* A chain of policies with duplicate indirect dependencies */
    test_policy = "test-duplicate-indirect-depends";
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-second");
    ret = policy_register(rlite::AddrAllocator::Prefix, test_policy + "-first",
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-first" << std::endl;
        return -1;
    }
    dependencies.clear();
    ret =
        policy_register(rlite::AddrAllocator::Prefix, test_policy + "-second");
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-second" << std::endl;
        return -1;
    }
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-first");
    ret = policy_register(rlite::UipcpRib::ResourceAllocPrefix, test_policy,
                          builder, {}, {}, dependencies);
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::UipcpRib::EnrollmentPrefix << " policy "
                  << test_policy << std::endl;
        return -1;
    }
    dependencies.clear();

    /* Cyclical dependencies */
    test_policy = "test-cyclic-depends";
    std::vector<
        std::tuple<const std::string &, const std::string &,
                   std::function<std::unique_ptr<rlite::Component>(UipcpRib *)>,
                   std::vector<std::string>,
                   std::vector<std::pair<std::string, rlite::PolicyParam>>,
                   std::vector<std::pair<std::string, std::string>>>>
        policies;

    using PolicyTuple =
        std::tuple<const std::string &, const std::string &,
                   std::function<std::unique_ptr<rlite::Component>(UipcpRib *)>,
                   std::vector<std::string>,
                   std::vector<std::pair<std::string, rlite::PolicyParam>>,
                   std::vector<std::pair<std::string, std::string>>>;

    policies.push_back(PolicyTuple(rlite::UipcpRib::EnrollmentPrefix,
                                   test_policy, builder, {}, {}, {}));
    policies.push_back(PolicyTuple(rlite::UipcpRib::ResourceAllocPrefix,
                                   test_policy, builder, {}, {}, {}));
    policies.push_back(PolicyTuple(rlite::AddrAllocator::Prefix, test_policy,
                                   builder, {}, {}, {}));
    ret = policy_register_group(policies);
    if (ret) {
        std::cout << "Failed to register policy group " << test_policy
                  << std::endl;
        return -1;
    }

    return 0;
}

int
main(int argc, char **argv)
{
    auto usage = []() {
        std::cout << "policy-deps-test -v be verbose\n"
                     "          -h show this help and exit\n";
    };
    int verbosity = 0;
    int opt;

    while ((opt = getopt(argc, argv, "hvn:")) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;

        case 'v':
            verbosity++;
            break;

        default:
            std::cout << "    Unrecognized option " << static_cast<char>(opt)
                      << std::endl;
            usage();
            return -1;
        }
    }

    char uipcp_name[32];
    struct uipcp uipcp;

    strncpy(uipcp_name, "policy-deps-test", sizeof(uipcp_name));
    uipcp.name       = uipcp_name;
    TestPolicyDeps test(&uipcp);
    if (test.init()) {
        std::cout << "Initialization of RIB for testing failed" << std::endl;
        return -1;
    }

    int ret = 0;
    std::string test_policy;

    /* Single policy without dependencies */
    test_policy = "test-no-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (!(ret == 0 &&
          test.policies[rlite::UipcpRib::EnrollmentPrefix] == test_policy)) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* Nonexisting dependency */
    test_policy = "test-false-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (ret == 0) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* A chain of policies with linear dependencies */
    test_policy = "test-linear-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (!(ret == 0 &&
          test.policies[rlite::UipcpRib::EnrollmentPrefix] == test_policy &&
          test.policies[rlite::UipcpRib::ResourceAllocPrefix] == test_policy &&
          test.policies[rlite::AddrAllocator::Prefix] == test_policy)) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* A chain of policies with duplicate direct dependencies */
    test_policy = "test-duplicate-direct-depends";
    std::vector<std::pair<std::string, std::string>> dependencies;
    test.policy_register(rlite::AddrAllocator::Prefix, test_policy + "-first");
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-first" << std::endl;
        return -1;
    }
    test.policy_register(rlite::AddrAllocator::Prefix, test_policy + "-second");
    if (ret) {
        std::cout << "Failed to register component "
                  << rlite::AddrAllocator::Prefix << " policy " << test_policy
                  << "-second" << std::endl;
        return -1;
    }
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-first");
    dependencies.emplace_back(rlite::AddrAllocator::Prefix,
                              test_policy + "-second");
    ret = test.policy_register(rlite::UipcpRib::ResourceAllocPrefix,
                               test_policy, test.builder, {}, {}, dependencies);
    if (ret == 0) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }
    dependencies.clear();

    /* A chain of policies with duplicate indirect dependencies */
    test_policy = "test-duplicate-indirect-depends";
    ret = test.policy_mod(rlite::UipcpRib::ResourceAllocPrefix, test_policy);
    if (ret == 0) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    /* Cyclical dependencies */
    test_policy = "test-cyclic-depends";
    ret = test.policy_mod(rlite::UipcpRib::EnrollmentPrefix, test_policy);
    if (!(ret == 0 &&
          test.policies[rlite::UipcpRib::EnrollmentPrefix] == test_policy &&
          test.policies[rlite::UipcpRib::ResourceAllocPrefix] == test_policy &&
          test.policies[rlite::AddrAllocator::Prefix] == test_policy)) {
        std::cout << "Test " << test_policy << " failed" << std::endl;
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of DO++, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#if defined(_WIN32) || defined(_WIN32_WCE)
# define NOMINMAX
# include <windows.h>
#endif
#include <DO/ImageIO/ImageIO.hpp>
#include <DO/Core/Image.hpp>
#include <DO/ImageIO/ImageIOObjects.hpp>

using namespace std;

namespace DO {

  static
  inline string fileExtension(const string& filepath)
  {
    string ext( filepath.substr(filepath.find_last_of(".")) );
    transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
    return ext;
  }

  static
  inline bool isJpegFileExt(const string& ext)
  {
    return
      ext == ".jpg"  ||
      ext == ".jpeg" ||
      ext == ".jpe"  ||
      ext == ".jfif" ||
      ext == ".jfi";
  }

  static
  inline bool isPngFileExt(const string& ext)
  {
    return ext == ".png";
  }

  static
  inline bool isTiffFileExt(const string& ext)
  {
    return
      ext == ".tif" ||
      ext == ".tiff";
  }

  static
  bool imread(unsigned char *& data, int& w, int& h, int& d,
              const string& filePath)
  {
    data = 0;
    w = h = d = 0;

    string ext(fileExtension(filePath));

    if ( isJpegFileExt(ext) &&
         JpegFileReader(filePath)(data, w, h, d) )
      return true;
    if ( isPngFileExt(ext) &&
         PngFileReader(filePath)(data, w, h, d) )
      return true;
    if ( isTiffFileExt(ext) &&
         TiffFileReader(filePath)(data, w, h, d) )
      return true;

    cerr << "Image format: " << ext << " either currently unsupported or invalid" << endl;
    return false;
  }

  bool readExifInfo(EXIFInfo& exifInfo, const std::string& filePath)
  {
    // Read the JPEG file into a buffer
    FILE *fp = fopen(filePath.c_str(), "rb");
    if (!fp) {
      cout << "Can't open file:" << endl << filePath << endl;
      return false;
    }
    fseek(fp, 0, SEEK_END);
    unsigned long fsize = ftell(fp);
    rewind(fp);
    unsigned char *buf = new unsigned char[fsize];
    if (fread(buf, 1, fsize, fp) != fsize) {
      cout << "Can't read file: " << endl << filePath << endl;
      delete[] buf;
      return false;
    }
    fclose(fp);

    // Parse EXIF
    int code = exifInfo.parseFrom(buf, fsize);
    delete[] buf;
    if (code) {
      //cout << "Error parsing EXIF: code " << code << endl;
      return false;
    }
    return true;
  }

  void print(const EXIFInfo& exifInfo)
  {
    printf("Camera make       : %s\n", exifInfo.Make.c_str());
    printf("Camera model      : %s\n", exifInfo.Model.c_str());
    printf("Software          : %s\n", exifInfo.Software.c_str());
    printf("Bits per sample   : %d\n", exifInfo.BitsPerSample);
    printf("Image width       : %d\n", exifInfo.ImageWidth);
    printf("Image height      : %d\n", exifInfo.ImageHeight);
    printf("Image description : %s\n", exifInfo.ImageDescription.c_str());
    printf("Image orientation : %d\n", exifInfo.Orientation);
    printf("Image copyright   : %s\n", exifInfo.Copyright.c_str());
    printf("Image date/time   : %s\n", exifInfo.DateTime.c_str());
    printf("Original date/time: %s\n", exifInfo.DateTimeOriginal.c_str());
    printf("Digitize date/time: %s\n", exifInfo.DateTimeDigitized.c_str());
    printf("Subsecond time    : %s\n", exifInfo.SubSecTimeOriginal.c_str());
    printf("Exposure time     : 1/%d s\n", (unsigned) (1.0/exifInfo.ExposureTime));
    printf("F-stop            : f/%.1f\n", exifInfo.FNumber);
    printf("ISO speed         : %d\n", exifInfo.ISOSpeedRatings);
    printf("Subject distance  : %f m\n", exifInfo.SubjectDistance);
    printf("Exposure bias     : %f EV\n", exifInfo.ExposureBiasValue);
    printf("Flash used?       : %d\n", exifInfo.Flash);
    printf("Metering mode     : %d\n", exifInfo.MeteringMode);
    printf("Lens focal length : %f mm\n", exifInfo.FocalLength);
    printf("35mm focal length : %u mm\n", exifInfo.FocalLengthIn35mm);
    printf("GPS Latitude      : %f deg (%f deg, %f min, %f sec %c)\n",
      exifInfo.GeoLocation.Latitude,
      exifInfo.GeoLocation.LatComponents.degrees,
      exifInfo.GeoLocation.LatComponents.minutes,
      exifInfo.GeoLocation.LatComponents.seconds,
      exifInfo.GeoLocation.LatComponents.direction);
    printf("GPS Longitude     : %f deg (%f deg, %f min, %f sec %c)\n",
      exifInfo.GeoLocation.Longitude,
      exifInfo.GeoLocation.LonComponents.degrees,
      exifInfo.GeoLocation.LonComponents.minutes,
      exifInfo.GeoLocation.LonComponents.seconds,
      exifInfo.GeoLocation.LonComponents.direction);
    printf("GPS Altitude      : %f m\n", exifInfo.GeoLocation.Altitude);
  }

  bool imread(Image<unsigned char>& image, const std::string& filePath)
  {
    unsigned char *data;
    int w, h, d;

    if (!imread(data, w, h, d, filePath))
      return false;

    // Wrap data and get data ownership
    if (d == 1)
      image = Image<unsigned char>(&data[0], Vector2i(w,h), true);
    if (d == 3)
      image = Image<Rgb8>(reinterpret_cast<Rgb8 *>(&data[0]), Vector2i(w,h), true)
        .convert<unsigned char>();
    if (d == 4)
      image = Image<Rgba8>(reinterpret_cast<Rgba8 *>(&data[0]), Vector2i(w,h), true)
        .convert<unsigned char>();

    EXIFInfo info;
    if (readExifInfo(info, filePath))
      flip(image, int(info.Orientation));

    return true;
  }

  bool imread(Image<Rgb8>& image, const std::string& filePath)
  {
    unsigned char *data;
    int w, h, d;

    if (!imread(data, w, h, d, filePath))
      return false;

    // Wrap data and get data ownership
    if (d == 1) {
      image = Image<unsigned char>(&data[0], Vector2i(w,h), true)
        .convert<Rgb8>();
    } else if (d == 3) {
      image = Image<Rgb8>(reinterpret_cast<Rgb8 *>(&data[0]), Vector2i(w,h), true);
    } else if (d == 4) {
      image = Image<Rgba8>(reinterpret_cast<Rgba8 *>(&data[0]), Vector2i(w,h), true)
        .convert<Rgb8>();
    }

    EXIFInfo info;
    if (readExifInfo(info, filePath))
      flip(image, int(info.Orientation));

    return true;
  }

  bool saveJpeg(const Image<Rgb8>& image, const std::string& filePath,
                int quality)
  {
    JpegFileWriter jpegWriter(
      reinterpret_cast<const unsigned char *>(image.data()),
      image.width(), image.height(), 3);
    return jpegWriter(filePath, quality);
  }

} /* namespace DO */<commit_msg>Fix and clean up code.<commit_after>// ========================================================================== //
// This file is part of DO++, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2013 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <vector>

#if defined(_WIN32) || defined(_WIN32_WCE)
# define NOMINMAX
# include <windows.h>
#endif

#include <DO/ImageIO/ImageIO.hpp>
#include <DO/Core/Image.hpp>
#include <DO/ImageIO/ImageIOObjects.hpp>

using namespace std;

// Utilities.
namespace DO {

  static inline string file_ext(const string& filepath)
  {
    string ext( filepath.substr(filepath.find_last_of(".")) );
    transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
    return ext;
  }

  static inline bool is_jpeg_file_ext(const string& ext)
  {
    return
      ext == ".jpg"  ||
      ext == ".jpeg" ||
      ext == ".jpe"  ||
      ext == ".jfif" ||
      ext == ".jfi";
  }

  static inline bool is_png_file_ext(const string& ext)
  {
    return ext == ".png";
  }

  static inline bool is_tiff_file_ext(const string& ext)
  {
    return
      ext == ".tif" ||
      ext == ".tiff";
  }

}

// Exif info.
namespace DO {

  bool read_exif_info(EXIFInfo& exif_info, const std::string& file_path)
  {
    // Read the JPEG file into a buffer
    FILE *fp = fopen(file_path.c_str(), "rb");
    if (!fp) {
      cout << "Can't open file:" << endl << file_path << endl;
      return false;
    }
    fseek(fp, 0, SEEK_END);
    unsigned long fsize = ftell(fp);
    rewind(fp);

    vector<unsigned char> buf(fsize);
    if (fread(&buf[0], 1, fsize, fp) != fsize) {
      cout << "Can't read file: " << endl << file_path << endl;
      return false;
    }
    fclose(fp);

    // Parse EXIF
    int code = exif_info.parseFrom(&buf[0], fsize);

    return !code;
  }

  std::ostream& operator<<(std::ostream& os, const EXIFInfo& exifInfo)
  {
    vector<char> buffer(1000);
    int length;
    string exif_info_string;

    length = sprintf(&buffer[0], "Camera make       : %s\n", exifInfo.Make.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Camera model      : %s\n", exifInfo.Model.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Software          : %s\n", exifInfo.Software.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Bits per sample   : %d\n", exifInfo.BitsPerSample);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Image width       : %d\n", exifInfo.ImageWidth);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Image height      : %d\n", exifInfo.ImageHeight);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Image description : %s\n", exifInfo.ImageDescription.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Image orientation : %d\n", exifInfo.Orientation);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Image copyright   : %s\n", exifInfo.Copyright.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Image date/time   : %s\n", exifInfo.DateTime.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Original date/time: %s\n", exifInfo.DateTimeOriginal.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Digitize date/time: %s\n", exifInfo.DateTimeDigitized.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Subsecond time    : %s\n", exifInfo.SubSecTimeOriginal.c_str());
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Exposure time     : 1/%d s\n", (unsigned) (1.0/exifInfo.ExposureTime));
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "F-stop            : f/%.1f\n", exifInfo.FNumber);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "ISO speed         : %d\n", exifInfo.ISOSpeedRatings);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Subject distance  : %f m\n", exifInfo.SubjectDistance);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Exposure bias     : %f EV\n", exifInfo.ExposureBiasValue);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Flash used?       : %d\n", exifInfo.Flash);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Metering mode     : %d\n", exifInfo.MeteringMode);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "Lens focal length : %f mm\n", exifInfo.FocalLength);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "35mm focal length : %u mm\n", exifInfo.FocalLengthIn35mm);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "GPS Latitude      : %f deg (%f deg, %f min, %f sec %c)\n",
      exifInfo.GeoLocation.Latitude,
      exifInfo.GeoLocation.LatComponents.degrees,
      exifInfo.GeoLocation.LatComponents.minutes,
      exifInfo.GeoLocation.LatComponents.seconds,
      exifInfo.GeoLocation.LatComponents.direction);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    length = sprintf(&buffer[0], "GPS Longitude     : %f deg (%f deg, %f min, %f sec %c)\n",
      exifInfo.GeoLocation.Longitude,
      exifInfo.GeoLocation.LonComponents.degrees,
      exifInfo.GeoLocation.LonComponents.minutes,
      exifInfo.GeoLocation.LonComponents.seconds,
      exifInfo.GeoLocation.LonComponents.direction);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    // GPS altitude.
    length = sprintf(&buffer[0], "GPS Altitude      : %f m\n", exifInfo.GeoLocation.Altitude);
    exif_info_string += string(&buffer[0], &buffer[0]+length);

    os << exif_info_string;
    return os;
  }

}

// Image read/write.
namespace DO {

  static
  bool imread(unsigned char *& data, int& w, int& h, int& d,
              const string& filepath)
  {
    data = 0;
    w = h = d = 0;

    string ext(file_ext(filepath));

    if ( is_jpeg_file_ext(ext) &&
         JpegFileReader(filepath).read(data, w, h, d) )
      return true;
    if ( is_png_file_ext(ext) &&
         PngFileReader(filepath).read(data, w, h, d) )
      return true;
    if ( is_tiff_file_ext(ext) &&
         TiffFileReader(filepath).read(data, w, h, d) )
      return true;

    cerr << "Image format: " << ext << " either currently unsupported or invalid" << endl;
    return false;
  }

  bool imread(Image<unsigned char>& image, const std::string& filepath)
  {
    unsigned char *data;
    int w, h, d;

    if (!imread(data, w, h, d, filepath))
      return false;

    // Wrap data and get data ownership
    if (d == 1)
      image = Image<unsigned char>(&data[0], Vector2i(w,h), true);
    if (d == 3)
      image = Image<Rgb8>(reinterpret_cast<Rgb8 *>(&data[0]), Vector2i(w,h), true)
        .convert<unsigned char>();
    if (d == 4)
      image = Image<Rgba8>(reinterpret_cast<Rgba8 *>(&data[0]), Vector2i(w,h), true)
        .convert<unsigned char>();

    EXIFInfo info;
    if (read_exif_info(info, filepath))
      flip(image, int(info.Orientation));

    return true;
  }

  bool imread(Image<Rgb8>& image, const std::string& filepath)
  {
    unsigned char *data;
    int w, h, d;

    if (!imread(data, w, h, d, filepath))
      return false;

    // Wrap data and get data ownership
    if (d == 1)
      image = Image<unsigned char>(&data[0], Vector2i(w,h), true).convert<Rgb8>();
    else if (d == 3)
      image = Image<Rgb8>(reinterpret_cast<Rgb8 *>(&data[0]), Vector2i(w,h), true);
    else if (d == 4)
      image = Image<Rgba8>(reinterpret_cast<Rgba8 *>(&data[0]), Vector2i(w,h), true)
        .convert<Rgb8>();

    EXIFInfo info;
    if (read_exif_info(info, filepath))
      flip(image, int(info.Orientation));

    return true;
  }

  bool save_jpeg(const Image<Rgb8>& image, const std::string& filepath,
                 int quality)
  {
    JpegFileWriter jpeg_writer(
      reinterpret_cast<const unsigned char *>(image.data()),
      image.width(), image.height(), 3);
    return jpeg_writer.write(filepath, quality);
  }

} /* namespace DO */<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

// ospray
#include "Device.h"
#include "common/OSPCommon.h"
#include "objectFactory.h"
// ospcommon
#include "ospcommon/os/library.h"
#include "ospcommon/utility/getEnvVar.h"
#include "ospcommon/tasking/tasking_system_init.h"

#include <map>

namespace ospray {
  namespace api {

    // Helper functions ///////////////////////////////////////////////////////

    template <typename OSTREAM_T>
    static inline void installStatusMsgFunc(Device& device, OSTREAM_T &stream)
    {
      device.msg_fcn = [&](const char *msg){ stream << msg; };
    }

    template <typename OSTREAM_T>
    static inline void installErrorMsgFunc(Device& device, OSTREAM_T &stream)
    {
      device.error_fcn = [&](OSPError e, const char *msg) {
        stream << "OSPRAY ERROR [" << e << "]: " << msg << std::endl;
      };
    }

    // Device definitions /////////////////////////////////////////////////////

    memory::IntrusivePtr<Device> Device::current;
    uint32_t Device::logLevel = 0;

    Device *Device::createDevice(const char *type)
    {
      // NOTE(jda) - If a user is manually creating the device (i.e. not using
      //             ospInit() to do it), then we need to check if there's a
      //             valid library for core ospray in our main symbol lookup
      //             table.
      auto &repo = *LibraryRepository::getInstance();
      if (!repo.libraryExists("ospray")) {
        repo.addDefaultLibrary();
        // also load the local device, otherwise ospNewDevice("default") fails
        repo.add("ospray_module_ispc");
      }

      return objectFactory<Device, OSP_DEVICE>(type);
    }

    void Device::commit()
    {
      auto OSPRAY_DEBUG = utility::getEnvVar<int>("OSPRAY_DEBUG");
      debugMode = OSPRAY_DEBUG.value_or(getParam<bool>("debug", 0));

      auto OSPRAY_TRACE_API = utility::getEnvVar<int>("OSPRAY_TRACE_API");
      bool traceAPI = OSPRAY_TRACE_API.value_or(getParam<bool>("traceApi", 0));

      if (traceAPI && !apiTraceEnabled) {
        auto streamPtr =
          std::make_shared<std::ofstream>("ospray_api_trace.txt");

        trace_fcn = [=](const char *message) {
          auto &stream = *streamPtr;
          stream << message << std::endl;
        };
      } else if (!traceAPI) {
        trace_fcn = [](const char *) {};
      }

      apiTraceEnabled = traceAPI;

      auto OSPRAY_LOG_LEVEL = utility::getEnvVar<int>("OSPRAY_LOG_LEVEL");
      logLevel = OSPRAY_LOG_LEVEL.value_or(getParam<int>("logLevel", 0));

      auto OSPRAY_THREADS = utility::getEnvVar<int>("OSPRAY_THREADS");
      numThreads = OSPRAY_THREADS.value_or(getParam<int>("numThreads", -1));

      auto OSPRAY_LOG_OUTPUT =
          utility::getEnvVar<std::string>("OSPRAY_LOG_OUTPUT");

      auto dst = OSPRAY_LOG_OUTPUT.value_or(
        getParam<std::string>("logOutput", "")
      );

      if (dst == "cout")
        installStatusMsgFunc(*this, std::cout);
      else if (dst == "cerr")
        installStatusMsgFunc(*this, std::cerr);
      else if (dst == "none")
        msg_fcn = [](const char*){};

      auto OSPRAY_ERROR_OUTPUT =
          utility::getEnvVar<std::string>("OSPRAY_ERROR_OUTPUT");

      dst = OSPRAY_ERROR_OUTPUT.value_or(
        getParam<std::string>("errorOutput", "")
      );

      if (dst == "cout")
        installErrorMsgFunc(*this, std::cout);
      else if (dst == "cerr")
        installErrorMsgFunc(*this, std::cerr);
      else if (dst == "none")
        error_fcn = [](OSPError, const char*){};

      if (debugMode) {
        logLevel   = 2;
        numThreads = 1;
        installStatusMsgFunc(*this, std::cout);
        installErrorMsgFunc(*this, std::cerr);
      }

      threadAffinity = AUTO_DETECT;

      auto OSPRAY_SET_AFFINITY = utility::getEnvVar<int>("OSPRAY_SET_AFFINITY");
      if (OSPRAY_SET_AFFINITY)
        threadAffinity = OSPRAY_SET_AFFINITY.value();

      threadAffinity = getParam<int>("setAffinity", threadAffinity);

      tasking::initTaskingSystem(numThreads);

      committed = true;
    }

    bool Device::isCommitted()
    {
      return committed;
    }

    bool deviceIsSet()
    {
      return Device::current.ptr != nullptr;
    }

    Device &currentDevice()
    {
      return *Device::current;
    }

    std::string generateEmbreeDeviceCfg(const Device &device)
    {
      std::stringstream embreeConfig;

      if (device.debugMode)
        embreeConfig << " verbose=2";

      if (device.threadAffinity == api::Device::AFFINITIZE)
        embreeConfig << ",set_affinity=1";
      else if (device.threadAffinity == api::Device::DEAFFINITIZE)
        embreeConfig << ",set_affinity=0";

      return embreeConfig.str();
    }

    int64_t Device::getProperty(const OSPDeviceProperty prop)
    {
      /* documented properties */
      switch (prop)
      {
      case OSP_DEVICE_VERSION           :
          return 10000*OSPRAY_VERSION_MAJOR + 100*OSPRAY_VERSION_MINOR + OSPRAY_VERSION_PATCH;
      case OSP_DEVICE_VERSION_MAJOR     : return OSPRAY_VERSION_MAJOR;
      case OSP_DEVICE_VERSION_MINOR     : return OSPRAY_VERSION_MINOR;
      case OSP_DEVICE_VERSION_PATCH     : return OSPRAY_VERSION_PATCH;
      case OSP_DEVICE_SO_VERSION        : return OSPRAY_SOVERSION;
      default: handleError(OSP_INVALID_ARGUMENT, "unknown readable property");
      return 0;
      }
    }
  } // ::ospray::api

  OSPTYPEFOR_DEFINITION(api::Device *);

} // ::ospray
<commit_msg>make env vars consistent with cmd line args<commit_after>// ======================================================================== //
// Copyright 2009-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

// ospray
#include "Device.h"
#include "common/OSPCommon.h"
#include "objectFactory.h"
// ospcommon
#include "ospcommon/os/library.h"
#include "ospcommon/utility/getEnvVar.h"
#include "ospcommon/tasking/tasking_system_init.h"

#include <map>

namespace ospray {
  namespace api {

    // Helper functions ///////////////////////////////////////////////////////

    template <typename OSTREAM_T>
    static inline void installStatusMsgFunc(Device& device, OSTREAM_T &stream)
    {
      device.msg_fcn = [&](const char *msg){ stream << msg; };
    }

    template <typename OSTREAM_T>
    static inline void installErrorMsgFunc(Device& device, OSTREAM_T &stream)
    {
      device.error_fcn = [&](OSPError e, const char *msg) {
        stream << "OSPRAY ERROR [" << e << "]: " << msg << std::endl;
      };
    }

    // Device definitions /////////////////////////////////////////////////////

    memory::IntrusivePtr<Device> Device::current;
    uint32_t Device::logLevel = 0;

    Device *Device::createDevice(const char *type)
    {
      // NOTE(jda) - If a user is manually creating the device (i.e. not using
      //             ospInit() to do it), then we need to check if there's a
      //             valid library for core ospray in our main symbol lookup
      //             table.
      auto &repo = *LibraryRepository::getInstance();
      if (!repo.libraryExists("ospray")) {
        repo.addDefaultLibrary();
        // also load the local device, otherwise ospNewDevice("default") fails
        repo.add("ospray_module_ispc");
      }

      return objectFactory<Device, OSP_DEVICE>(type);
    }

    void Device::commit()
    {
      auto OSPRAY_DEBUG = utility::getEnvVar<int>("OSPRAY_DEBUG");
      debugMode = OSPRAY_DEBUG.value_or(getParam<bool>("debug", 0));

      auto OSPRAY_TRACE_API = utility::getEnvVar<int>("OSPRAY_TRACE_API");
      bool traceAPI = OSPRAY_TRACE_API.value_or(getParam<bool>("traceApi", 0));

      if (traceAPI && !apiTraceEnabled) {
        auto streamPtr =
          std::make_shared<std::ofstream>("ospray_api_trace.txt");

        trace_fcn = [=](const char *message) {
          auto &stream = *streamPtr;
          stream << message << std::endl;
        };
      } else if (!traceAPI) {
        trace_fcn = [](const char *) {};
      }

      apiTraceEnabled = traceAPI;

      auto OSPRAY_LOG_LEVEL = utility::getEnvVar<int>("OSPRAY_LOG_LEVEL");
      logLevel = OSPRAY_LOG_LEVEL.value_or(getParam<int>("logLevel", 0));

      auto OSPRAY_NUM_THREADS = utility::getEnvVar<int>("OSPRAY_NUM_THREADS");
      numThreads = OSPRAY_NUM_THREADS.value_or(getParam<int>("numThreads", -1));

      auto OSPRAY_LOG_OUTPUT =
          utility::getEnvVar<std::string>("OSPRAY_LOG_OUTPUT");

      auto dst = OSPRAY_LOG_OUTPUT.value_or(
        getParam<std::string>("logOutput", "")
      );

      if (dst == "cout")
        installStatusMsgFunc(*this, std::cout);
      else if (dst == "cerr")
        installStatusMsgFunc(*this, std::cerr);
      else if (dst == "none")
        msg_fcn = [](const char*){};

      auto OSPRAY_ERROR_OUTPUT =
          utility::getEnvVar<std::string>("OSPRAY_ERROR_OUTPUT");

      dst = OSPRAY_ERROR_OUTPUT.value_or(
        getParam<std::string>("errorOutput", "")
      );

      if (dst == "cout")
        installErrorMsgFunc(*this, std::cout);
      else if (dst == "cerr")
        installErrorMsgFunc(*this, std::cerr);
      else if (dst == "none")
        error_fcn = [](OSPError, const char*){};

      if (debugMode) {
        logLevel   = 2;
        numThreads = 1;
        installStatusMsgFunc(*this, std::cout);
        installErrorMsgFunc(*this, std::cerr);
      }

      threadAffinity = AUTO_DETECT;

      auto OSPRAY_SET_AFFINITY = utility::getEnvVar<int>("OSPRAY_SET_AFFINITY");
      if (OSPRAY_SET_AFFINITY)
        threadAffinity = OSPRAY_SET_AFFINITY.value();

      threadAffinity = getParam<int>("setAffinity", threadAffinity);

      tasking::initTaskingSystem(numThreads);

      committed = true;
    }

    bool Device::isCommitted()
    {
      return committed;
    }

    bool deviceIsSet()
    {
      return Device::current.ptr != nullptr;
    }

    Device &currentDevice()
    {
      return *Device::current;
    }

    std::string generateEmbreeDeviceCfg(const Device &device)
    {
      std::stringstream embreeConfig;

      if (device.debugMode)
        embreeConfig << " verbose=2";

      if (device.threadAffinity == api::Device::AFFINITIZE)
        embreeConfig << ",set_affinity=1";
      else if (device.threadAffinity == api::Device::DEAFFINITIZE)
        embreeConfig << ",set_affinity=0";

      return embreeConfig.str();
    }

    int64_t Device::getProperty(const OSPDeviceProperty prop)
    {
      /* documented properties */
      switch (prop)
      {
      case OSP_DEVICE_VERSION           :
          return 10000*OSPRAY_VERSION_MAJOR + 100*OSPRAY_VERSION_MINOR + OSPRAY_VERSION_PATCH;
      case OSP_DEVICE_VERSION_MAJOR     : return OSPRAY_VERSION_MAJOR;
      case OSP_DEVICE_VERSION_MINOR     : return OSPRAY_VERSION_MINOR;
      case OSP_DEVICE_VERSION_PATCH     : return OSPRAY_VERSION_PATCH;
      case OSP_DEVICE_SO_VERSION        : return OSPRAY_SOVERSION;
      default: handleError(OSP_INVALID_ARGUMENT, "unknown readable property");
      return 0;
      }
    }
  } // ::ospray::api

  OSPTYPEFOR_DEFINITION(api::Device *);

} // ::ospray
<|endoftext|>