<commit_before>/*
    kopeteidentity.cpp - Kopete Identity

    Copyright (c) 2007      by Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
              (c) 2007         Will Stephenson <wstephenson@kde.org>

    Kopete    (c) 2002-2007 by the Kopete developers  <kopete-devel@kde.org>

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

#include "kopetepropertycontainer.h"
#include "kopeteidentity.h"
#include "kopeteaccount.h"
#include "kopetecontact.h"
#include "kopeteprotocol.h"

#include <QStringList>
#include <KDebug>
#include <KConfigGroup>
#include <KGlobal>
#include <KSharedConfigPtr>
#include <KLocale>
#include <KRandom>
#include <KMenu>

#include <kdeversion.h>

namespace Kopete
{

class Identity::Private
{
public:
	Private(const QString &i, const QString &l) : onlineStatus( OnlineStatus::Unknown )
	{
		id = i;
		label = l;
		configGroup = new KConfigGroup(KGlobal::config(), QString::fromLatin1( "Identity_%1" ).arg( id ));
	}
	QList<Kopete::Account*> accounts;
	QString id;
	QString label;
	KConfigGroup *configGroup;
	OnlineStatus::StatusType onlineStatus;
	QString statusMessage;
};

Identity::Identity( const QString &id, const QString &label )
	: d( new Private(id, label) )
{
	load();
	connect(this, SIGNAL(propertyChanged(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)),
	        this, SLOT(slotSaveProperty(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)));
}

Identity::Identity(const QString &label)
: d( new Private(KRandom::randomString(10), label) )
{
	connect(this, SIGNAL(propertyChanged(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)),
	        this, SLOT(slotSaveProperty(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)));
}

Identity * Identity::clone() const
{
	Identity * id = new Identity( label() );
	QMap<QString,QString> props;
	serializeProperties( props );
	id->deserializeProperties( props );

	connect(id, SIGNAL(propertyChanged(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)),
			id, SLOT(slotSaveProperty(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)));
	return id;
}

Identity::~Identity()
{
	emit identityDestroyed(this);

	delete d->configGroup;
	delete d;
}

QString Identity::id() const
{
	return d->id;
}

QString Identity::label() const
{
	return d->label;
}

void Identity::setLabel(const QString& label)
{
	d->label = label;
}

bool Identity::excludeConnect() const
{
	//TODO implement
	return false;
}

void Identity::setOnlineStatus( uint category, const QString &awayMessage )
{
	OnlineStatusManager::Categories katgor=(OnlineStatusManager::Categories)category;

	d->statusMessage = awayMessage;
	foreach( Account *account ,  d->accounts )
	{
		Kopete::OnlineStatus status = OnlineStatusManager::self()->onlineStatus(account->protocol() , katgor);
		if ( !account->excludeConnect() )
			account->setOnlineStatus( status , awayMessage );
	}
}

OnlineStatus::StatusType Identity::onlineStatus() const
{
	return d->onlineStatus;
}

QString Identity::statusMessage() const
{
	return d->statusMessage;
}

QString Identity::toolTip() const
{

	QString tt = QLatin1String("<qt>");

	QString nick;
	if ( hasProperty(Kopete::Global::Properties::self()->nickName().key()) )
		nick = property(Kopete::Global::Properties::self()->nickName()).value().toString();
	else
		nick = d->label;

	tt+= i18nc( "Identity tooltip information: <nobr>ICON NAME</nobr>

",
				"<nobr> %2</nobr>

",
				QString(QUrl::toPercentEncoding( d->label )), nick );

	foreach(Account *a, d->accounts)
	{
		Kopete::Contact *self = a->myself();
		QString onlineStatus = self ? self->onlineStatus().description() : i18n("Offline");
		tt += i18nc( "Account tooltip information: <nobr>ICON PROTOCOL: NAME (STATUS)</nobr>
",
					 "<nobr> %1: %2 (%5)</nobr>
",
					 a->protocol()->displayName(), a->accountLabel(), QString(QUrl::toPercentEncoding( a->protocol()->pluginId() )),
					 QString(QUrl::toPercentEncoding( a->accountId() )), onlineStatus );
	}
	tt += QLatin1String("</qt>");
	return tt;
}

QString Identity::customIcon() const
{
	//TODO implement
	return "user";
}

QList<Account*> Identity::accounts() const
{
	return d->accounts;
}

void Identity::addAccount( Kopete::Account *account )
{
	// check if we already have this account
	if ( d->accounts.indexOf( account ) != -1 )
		return;

	d->accounts.append( account );

	connect( account->myself(),
			SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)),
			this, SLOT(updateOnlineStatus()));
	connect(account, SIGNAL(accountDestroyed(const Kopete::Account*)),
			this, SLOT(removeAccount(const Kopete::Account*)));

	updateOnlineStatus();
	emit identityChanged( this );
}

void Identity::removeAccount( const Kopete::Account *account )
{
	Kopete::Account *a = const_cast<Kopete::Account*>(account);
	if ( !d->accounts.contains( a ) )
		return;

	disconnect( account );
	d->accounts.removeAll( a );
	updateOnlineStatus();
	emit identityChanged( this );
}

KConfigGroup *Identity::configGroup() const
{
	return d->configGroup;
}

void Identity::load()
{
	QMap<QString,QString>::iterator it;

	QMap<QString,QString> props = d->configGroup->entryMap();
	deserializeProperties(props);
}

void Identity::save()
{
	// FIXME: using kconfig for now, but I guess this is going to change
	QMap<QString,QString> props;
	serializeProperties(props);
	QMap<QString,QString>::iterator it;
	for (it = props.begin(); it != props.end();  ++it)
	{
		d->configGroup->writeEntry(it.key(), it.value());
	}
}

void Identity::updateOnlineStatus()
{
	Kopete::OnlineStatus mostSignificantStatus;
	Kopete::OnlineStatus::StatusType newStatus = Kopete::OnlineStatus::Unknown;

	foreach(Account *account, d->accounts)
	{
		// find most significant status
		if ( account->myself() &&
			 account->myself()->onlineStatus() > mostSignificantStatus )
			mostSignificantStatus = account->myself()->onlineStatus();
	}

	newStatus = mostSignificantStatus.status();
	if( newStatus != d->onlineStatus )
	{
		d->onlineStatus = newStatus;
		emit onlineStatusChanged( this );
	}
}

void Identity::slotSaveProperty( Kopete::PropertyContainer *container, const QString &key,
		                const QVariant &oldValue, const QVariant &newValue )
{
	save();
}

} //END namespace Kopete

#include "kopeteidentity.moc"

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>BUG:152609 Implement Identity::customIcon()<commit_after>/*
    kopeteidentity.cpp - Kopete Identity

    Copyright (c) 2007      by Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
              (c) 2007         Will Stephenson <wstephenson@kde.org>

    Kopete    (c) 2002-2007 by the Kopete developers  <kopete-devel@kde.org>

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

#include "kopetepropertycontainer.h"
#include "kopeteidentity.h"
#include "kopeteaccount.h"
#include "kopetecontact.h"
#include "kopeteprotocol.h"

#include <QStringList>
#include <KDebug>
#include <KConfigGroup>
#include <KGlobal>
#include <KSharedConfigPtr>
#include <KLocale>
#include <KRandom>
#include <KMenu>

#include <kdeversion.h>

namespace Kopete
{

class Identity::Private
{
public:
	Private(const QString &i, const QString &l) : onlineStatus( OnlineStatus::Unknown )
	{
		id = i;
		label = l;
		configGroup = new KConfigGroup(KGlobal::config(), QString::fromLatin1( "Identity_%1" ).arg( id ));
	}
	QList<Kopete::Account*> accounts;
	QString id;
	QString label;
	KConfigGroup *configGroup;
	OnlineStatus::StatusType onlineStatus;
	QString statusMessage;
};

Identity::Identity( const QString &id, const QString &label )
	: d( new Private(id, label) )
{
	load();
	connect(this, SIGNAL(propertyChanged(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)),
	        this, SLOT(slotSaveProperty(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)));
}

Identity::Identity(const QString &label)
: d( new Private(KRandom::randomString(10), label) )
{
	connect(this, SIGNAL(propertyChanged(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)),
	        this, SLOT(slotSaveProperty(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)));
}

Identity * Identity::clone() const
{
	Identity * id = new Identity( label() );
	QMap<QString,QString> props;
	serializeProperties( props );
	id->deserializeProperties( props );

	connect(id, SIGNAL(propertyChanged(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)),
			id, SLOT(slotSaveProperty(Kopete::PropertyContainer*, const QString&, const QVariant &, const QVariant &)));
	return id;
}

Identity::~Identity()
{
	emit identityDestroyed(this);

	delete d->configGroup;
	delete d;
}

QString Identity::id() const
{
	return d->id;
}

QString Identity::label() const
{
	return d->label;
}

void Identity::setLabel(const QString& label)
{
	d->label = label;
}

bool Identity::excludeConnect() const
{
	//TODO implement
	return false;
}

void Identity::setOnlineStatus( uint category, const QString &awayMessage )
{
	OnlineStatusManager::Categories katgor=(OnlineStatusManager::Categories)category;

	d->statusMessage = awayMessage;
	foreach( Account *account ,  d->accounts )
	{
		Kopete::OnlineStatus status = OnlineStatusManager::self()->onlineStatus(account->protocol() , katgor);
		if ( !account->excludeConnect() )
			account->setOnlineStatus( status , awayMessage );
	}
}

OnlineStatus::StatusType Identity::onlineStatus() const
{
	return d->onlineStatus;
}

QString Identity::statusMessage() const
{
	return d->statusMessage;
}

QString Identity::toolTip() const
{

	QString tt = QLatin1String("<qt>");

	QString nick;
	if ( hasProperty(Kopete::Global::Properties::self()->nickName().key()) )
		nick = property(Kopete::Global::Properties::self()->nickName()).value().toString();
	else
		nick = d->label;

	tt+= i18nc( "Identity tooltip information: <nobr>ICON NAME</nobr>

",
				"<nobr> %2</nobr>

",
				QString(QUrl::toPercentEncoding( d->label )), nick );

	foreach(Account *a, d->accounts)
	{
		Kopete::Contact *self = a->myself();
		QString onlineStatus = self ? self->onlineStatus().description() : i18n("Offline");
		tt += i18nc( "Account tooltip information: <nobr>ICON PROTOCOL: NAME (STATUS)</nobr>
",
					 "<nobr> %1: %2 (%5)</nobr>
",
					 a->protocol()->displayName(), a->accountLabel(), QString(QUrl::toPercentEncoding( a->protocol()->pluginId() )),
					 QString(QUrl::toPercentEncoding( a->accountId() )), onlineStatus );
	}
	tt += QLatin1String("</qt>");
	return tt;
}

QString Identity::customIcon() const
{
	if (hasProperty( Kopete::Global::Properties::self()->photo().key() ))
		return property(Kopete::Global::Properties::self()->photo()).value().toString();
	else
		return "user";
}

QList<Account*> Identity::accounts() const
{
	return d->accounts;
}

void Identity::addAccount( Kopete::Account *account )
{
	// check if we already have this account
	if ( d->accounts.indexOf( account ) != -1 )
		return;

	d->accounts.append( account );

	connect( account->myself(),
			SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)),
			this, SLOT(updateOnlineStatus()));
	connect(account, SIGNAL(accountDestroyed(const Kopete::Account*)),
			this, SLOT(removeAccount(const Kopete::Account*)));

	updateOnlineStatus();
	emit identityChanged( this );
}

void Identity::removeAccount( const Kopete::Account *account )
{
	Kopete::Account *a = const_cast<Kopete::Account*>(account);
	if ( !d->accounts.contains( a ) )
		return;

	disconnect( account );
	d->accounts.removeAll( a );
	updateOnlineStatus();
	emit identityChanged( this );
}

KConfigGroup *Identity::configGroup() const
{
	return d->configGroup;
}

void Identity::load()
{
	QMap<QString,QString>::iterator it;

	QMap<QString,QString> props = d->configGroup->entryMap();
	deserializeProperties(props);
}

void Identity::save()
{
	// FIXME: using kconfig for now, but I guess this is going to change
	QMap<QString,QString> props;
	serializeProperties(props);
	QMap<QString,QString>::iterator it;
	for (it = props.begin(); it != props.end();  ++it)
	{
		d->configGroup->writeEntry(it.key(), it.value());
	}
}

void Identity::updateOnlineStatus()
{
	Kopete::OnlineStatus mostSignificantStatus;
	Kopete::OnlineStatus::StatusType newStatus = Kopete::OnlineStatus::Unknown;

	foreach(Account *account, d->accounts)
	{
		// find most significant status
		if ( account->myself() &&
			 account->myself()->onlineStatus() > mostSignificantStatus )
			mostSignificantStatus = account->myself()->onlineStatus();
	}

	newStatus = mostSignificantStatus.status();
	if( newStatus != d->onlineStatus )
	{
		d->onlineStatus = newStatus;
		emit onlineStatusChanged( this );
	}
}

void Identity::slotSaveProperty( Kopete::PropertyContainer *container, const QString &key,
		                const QVariant &oldValue, const QVariant &newValue )
{
	save();
}

} //END namespace Kopete

#include "kopeteidentity.moc"

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	binarystring.cxx
 *
 *   DESCRIPTION
 *      implementation of bytea (binary string) conversions
 *
 * Copyright (c) 2003-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <new>
#include <stdexcept>

#include "libpq-fe.h"

#include "pqxx/binarystring"

using namespace PGSTD;
using namespace pqxx::internal;

namespace
{
// Convert textual digit to value
inline char DV(unsigned char d) { return d - '0'; }
}

pqxx::binarystring::binarystring(const result::field &F) :
  super(),
  m_size(0)
{
  unsigned char *p = const_cast<unsigned char *>(
      reinterpret_cast<const_iterator>(F.c_str()));

#ifdef PQXX_HAVE_PQUNESCAPEBYTEA

  size_t sz = 0;
  super::operator=(PQunescapeBytea(p, &sz));
  if (!c_ptr()) throw bad_alloc();
  m_size = sz;

#else

  m_str.reserve(F.size()+1);
  for (result::field::size_type i=0; i<F.size(); ++i)
  {
    unsigned char c = p[i];
    if (c == '\\')
    {
      c = p[++i];
      if (isdigit(c) && isdigit(p[i+1]) && isdigit(p[i+2]))
      {
	c = (DV(p[c])<<9) | (DV(p[i+1])<<3) | DV(p[i+2]);
	i += 2;
      }
    }
    m_str += char(c);
  }

  m_size = m_str.size();
  void *buf = malloc(m_size+1);
  if (!buf)
    throw bad_alloc();
  super::operator=(static_cast<unsigned char *>(buf));
  strcpy(static_cast<char *>(buf), m_str.c_str());

#endif
}

bool pqxx::binarystring::operator==(const binarystring &rhs) const throw ()
{
  if (rhs.size() != size()) return false;
  for (size_type i=0; i<size(); ++i) if (rhs[i] != data()[i]) return false;
  return true;
}

pqxx::binarystring::const_reference pqxx::binarystring::at(size_type n) const
{
  if (n >= m_size)
  {
    if (!m_size)
      throw out_of_range("Accessing empty binarystring");
    throw out_of_range("binarystring index out of range: " +
	to_string(n) + " (should be below " + to_string(m_size) + ")");
  }
  return data()[n];
}

void pqxx::binarystring::swap(binarystring &rhs)
{
  // This might fail, so do it first
  m_str.swap(rhs.m_str);

  // PQAlloc<>::swap() is nothrow
  super::swap(rhs);

  // This part very obviously can't go wrong, so do it last
  const size_type s(m_size);
  m_size = rhs.m_size;
  rhs.m_size = s;
}

const string &pqxx::binarystring::str() const
{
  if (m_str.empty() && m_size) m_str = string(c_ptr(), m_size);
  return m_str;
}

string pqxx::escape_binary(const unsigned char bin[], size_t len)
{
#ifdef PQXX_HAVE_PQESCAPEBYTEA
  size_t escapedlen = 0;
  unsigned char *p = const_cast<unsigned char *>(bin);
  PQAlloc<unsigned char> A(PQescapeBytea(p, len, &escapedlen));
  const char *cstr = reinterpret_cast<const char *>(A.c_ptr());
  if (!cstr) throw bad_alloc();
  return string(cstr, escapedlen-1);
#else
  // TODO: Fails to escape "high" bytes!?
  string result;
  result.reserve(len);
  for (size_t i=0; i<len; ++i)
  {
    if (bin[i] & 0x80)
    {
      char buf[8];
      sprintf(buf, "\\\\%03o", unsigned(bin[i]));
      result += buf;
    }
    else switch (bin[i])
    {
    case 0:
      result += "\\\\000";
      break;

    case '\'':
      result += "\\'";
      break;

    case '\\':
      result += "\\\\\\\\";
      break;

    default:
      result += char(bin[i]);
    }
  }
  return result;
#endif
}

string pqxx::escape_binary(const unsigned char bin[])
{
  return escape_binary(bin, strlen(reinterpret_cast<const char *>(bin)));
}

string pqxx::escape_binary(const char bin[], size_t len)
{
  return escape_binary(reinterpret_cast<const unsigned char *>(bin), len);
}

string pqxx::escape_binary(const char bin[])
{
  return escape_binary(bin, strlen(bin));
}

string pqxx::escape_binary(const string &bin)
{
  return escape_binary(bin.c_str(), bin.size());
}

<commit_msg>Removed unneeded "+1" in string reservation<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	binarystring.cxx
 *
 *   DESCRIPTION
 *      implementation of bytea (binary string) conversions
 *
 * Copyright (c) 2003-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <new>
#include <stdexcept>

#include "libpq-fe.h"

#include "pqxx/binarystring"

using namespace PGSTD;
using namespace pqxx::internal;

namespace
{
// Convert textual digit to value
inline char DV(unsigned char d) { return d - '0'; }
}

pqxx::binarystring::binarystring(const result::field &F) :
  super(),
  m_size(0)
{
  unsigned char *p = const_cast<unsigned char *>(
      reinterpret_cast<const_iterator>(F.c_str()));

#ifdef PQXX_HAVE_PQUNESCAPEBYTEA

  size_t sz = 0;
  super::operator=(PQunescapeBytea(p, &sz));
  if (!c_ptr()) throw bad_alloc();
  m_size = sz;

#else

  m_str.reserve(F.size());
  for (result::field::size_type i=0; i<F.size(); ++i)
  {
    unsigned char c = p[i];
    if (c == '\\')
    {
      c = p[++i];
      if (isdigit(c) && isdigit(p[i+1]) && isdigit(p[i+2]))
      {
	c = (DV(p[c])<<9) | (DV(p[i+1])<<3) | DV(p[i+2]);
	i += 2;
      }
    }
    m_str += char(c);
  }

  m_size = m_str.size();
  void *buf = malloc(m_size+1);
  if (!buf)
    throw bad_alloc();
  super::operator=(static_cast<unsigned char *>(buf));
  strcpy(static_cast<char *>(buf), m_str.c_str());

#endif
}

bool pqxx::binarystring::operator==(const binarystring &rhs) const throw ()
{
  if (rhs.size() != size()) return false;
  for (size_type i=0; i<size(); ++i) if (rhs[i] != data()[i]) return false;
  return true;
}

pqxx::binarystring::const_reference pqxx::binarystring::at(size_type n) const
{
  if (n >= m_size)
  {
    if (!m_size)
      throw out_of_range("Accessing empty binarystring");
    throw out_of_range("binarystring index out of range: " +
	to_string(n) + " (should be below " + to_string(m_size) + ")");
  }
  return data()[n];
}

void pqxx::binarystring::swap(binarystring &rhs)
{
  // This might fail, so do it first
  m_str.swap(rhs.m_str);

  // PQAlloc<>::swap() is nothrow
  super::swap(rhs);

  // This part very obviously can't go wrong, so do it last
  const size_type s(m_size);
  m_size = rhs.m_size;
  rhs.m_size = s;
}

const string &pqxx::binarystring::str() const
{
  if (m_str.empty() && m_size) m_str = string(c_ptr(), m_size);
  return m_str;
}

string pqxx::escape_binary(const unsigned char bin[], size_t len)
{
#ifdef PQXX_HAVE_PQESCAPEBYTEA
  size_t escapedlen = 0;
  unsigned char *p = const_cast<unsigned char *>(bin);
  PQAlloc<unsigned char> A(PQescapeBytea(p, len, &escapedlen));
  const char *cstr = reinterpret_cast<const char *>(A.c_ptr());
  if (!cstr) throw bad_alloc();
  return string(cstr, escapedlen-1);
#else
  // TODO: Fails to escape "high" bytes!?
  string result;
  result.reserve(len);
  for (size_t i=0; i<len; ++i)
  {
    if (bin[i] & 0x80)
    {
      char buf[8];
      sprintf(buf, "\\\\%03o", unsigned(bin[i]));
      result += buf;
    }
    else switch (bin[i])
    {
    case 0:
      result += "\\\\000";
      break;

    case '\'':
      result += "\\'";
      break;

    case '\\':
      result += "\\\\\\\\";
      break;

    default:
      result += char(bin[i]);
    }
  }
  return result;
#endif
}

string pqxx::escape_binary(const unsigned char bin[])
{
  return escape_binary(bin, strlen(reinterpret_cast<const char *>(bin)));
}

string pqxx::escape_binary(const char bin[], size_t len)
{
  return escape_binary(reinterpret_cast<const unsigned char *>(bin), len);
}

string pqxx::escape_binary(const char bin[])
{
  return escape_binary(bin, strlen(bin));
}

string pqxx::escape_binary(const string &bin)
{
  return escape_binary(bin.c_str(), bin.size());
}

<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	binarystring.cxx
 *
 *   DESCRIPTION
 *      implementation of bytea (binary string) conversions
 *
 * Copyright (c) 2003-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <new>
#include <stdexcept>

#include "pqxx/binarystring"

using namespace PGSTD;
using namespace pqxx::internal;
using namespace pqxx::internal::pq;

namespace
{
// Convert textual digit to value
inline char DV(unsigned char d) { return d - '0'; }
}

pqxx::binarystring::binarystring(const result::field &F) :
  super(),
  m_size(0)
{
  unsigned char *p = const_cast<unsigned char *>(
      reinterpret_cast<const_iterator>(F.c_str()));

#ifdef PQXX_HAVE_PQUNESCAPEBYTEA

  size_t sz = 0;
  super::operator=(PQunescapeBytea(p, &sz));
  if (!c_ptr()) throw bad_alloc();
  m_size = sz;

#else

  m_str.reserve(F.size());
  for (result::field::size_type i=0; i<F.size(); ++i)
  {
    unsigned char c = p[i];
    if (c == '\\')
    {
      c = p[++i];
      if (isdigit(c) && isdigit(p[i+1]) && isdigit(p[i+2]))
      {
	c = (DV(p[c])<<9) | (DV(p[i+1])<<3) | DV(p[i+2]);
	i += 2;
      }
    }
    m_str += char(c);
  }

  m_size = m_str.size();
  void *buf = malloc(m_size+1);
  if (!buf)
    throw bad_alloc();
  super::operator=(static_cast<unsigned char *>(buf));
  strcpy(static_cast<char *>(buf), m_str.c_str());

#endif
}

pqxx::binarystring::const_reference pqxx::binarystring::at(size_type n) const
{
  if (n >= m_size)
  {
    if (!m_size)
      throw out_of_range("Accessing empty binarystring");
    throw out_of_range("binarystring index out of range: " +
	to_string(n) + " (should be below " + to_string(m_size) + ")");
  }
  return data()[n];
}

void pqxx::binarystring::swap(binarystring &rhs)
{
  const size_type s(m_size);
  m_str.swap(rhs.m_str);
  m_size = rhs.m_size;
  rhs.m_size = s;
}

const string &pqxx::binarystring::str() const
{
  if (m_str.empty() && m_size) m_str = string(c_ptr(), m_size);
  return m_str;
}

string pqxx::escape_binary(const unsigned char bin[], size_t len)
{
#ifdef PQXX_HAVE_PQESCAPEBYTEA
  size_t escapedlen = 0;
  unsigned char *p = const_cast<unsigned char *>(bin);
  PQAlloc<unsigned char> A(PQescapeBytea(p, len, &escapedlen));
  const char *cstr = reinterpret_cast<const char *>(A.c_ptr());
  if (!cstr) throw bad_alloc();
  return string(cstr, escapedlen-1);
#else
  string result;
  result.reserve(len);
  for (size_t i=0; i<len; ++i)
  {
    if (bin[i] & 0x80)
    {
      char buf[8];
      sprintf(buf, "\\\\%03o", unsigned(bin[i]));
      result += buf;
    }
    else switch (bin[i])
    {
    case 0:
      result += "\\\\000";
      break;

    case '\'':
      result += "\\'";
      break;

    case '\\':
      result += "\\\\\\\\";
      break;

    default:
      result += char(bin[i]);
    }
  }
  return result;
#endif
}

string pqxx::escape_binary(const unsigned char bin[])
{
  return escape_binary(bin, strlen(reinterpret_cast<const char *>(bin)));
}

string pqxx::escape_binary(const char bin[], size_t len)
{
  return escape_binary(reinterpret_cast<const unsigned char *>(bin), len);
}

string pqxx::escape_binary(const char bin[])
{
  return escape_binary(bin, strlen(bin));
}

string pqxx::escape_binary(const string &bin)
{
  return escape_binary(bin.c_str(), bin.size());
}

<commit_msg>Fixed bug in swap(); added equality comparison<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	binarystring.cxx
 *
 *   DESCRIPTION
 *      implementation of bytea (binary string) conversions
 *
 * Copyright (c) 2003-2004, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <new>
#include <stdexcept>

#include "pqxx/binarystring"

using namespace PGSTD;
using namespace pqxx::internal;
using namespace pqxx::internal::pq;

namespace
{
// Convert textual digit to value
inline char DV(unsigned char d) { return d - '0'; }
}

pqxx::binarystring::binarystring(const result::field &F) :
  super(),
  m_size(0)
{
  unsigned char *p = const_cast<unsigned char *>(
      reinterpret_cast<const_iterator>(F.c_str()));

#ifdef PQXX_HAVE_PQUNESCAPEBYTEA

  size_t sz = 0;
  super::operator=(PQunescapeBytea(p, &sz));
  if (!c_ptr()) throw bad_alloc();
  m_size = sz;

#else

  m_str.reserve(F.size());
  for (result::field::size_type i=0; i<F.size(); ++i)
  {
    unsigned char c = p[i];
    if (c == '\\')
    {
      c = p[++i];
      if (isdigit(c) && isdigit(p[i+1]) && isdigit(p[i+2]))
      {
	c = (DV(p[c])<<9) | (DV(p[i+1])<<3) | DV(p[i+2]);
	i += 2;
      }
    }
    m_str += char(c);
  }

  m_size = m_str.size();
  void *buf = malloc(m_size+1);
  if (!buf)
    throw bad_alloc();
  super::operator=(static_cast<unsigned char *>(buf));
  strcpy(static_cast<char *>(buf), m_str.c_str());

#endif
}

bool pqxx::binarystring::operator==(const binarystring &rhs) const throw ()
{
  if (rhs.size() != size()) return false;
  for (size_type i=0; i<size(); ++i) if (rhs[i] != data()[i]) return false;
  return true;
}

pqxx::binarystring::const_reference pqxx::binarystring::at(size_type n) const
{
  if (n >= m_size)
  {
    if (!m_size)
      throw out_of_range("Accessing empty binarystring");
    throw out_of_range("binarystring index out of range: " +
	to_string(n) + " (should be below " + to_string(m_size) + ")");
  }
  return data()[n];
}

void pqxx::binarystring::swap(binarystring &rhs)
{
  const size_type s(m_size);
  // This can fail, so do it first
  m_str.swap(rhs.m_str);

  // PQAlloc<>::swap() is nothrow
  super::swap(rhs);

  // This part very obviously can't go wrong, so do it last
  m_size = rhs.m_size;
  rhs.m_size = s;
}

const string &pqxx::binarystring::str() const
{
  if (m_str.empty() && m_size) m_str = string(c_ptr(), m_size);
  return m_str;
}

string pqxx::escape_binary(const unsigned char bin[], size_t len)
{
#ifdef PQXX_HAVE_PQESCAPEBYTEA
  size_t escapedlen = 0;
  unsigned char *p = const_cast<unsigned char *>(bin);
  PQAlloc<unsigned char> A(PQescapeBytea(p, len, &escapedlen));
  const char *cstr = reinterpret_cast<const char *>(A.c_ptr());
  if (!cstr) throw bad_alloc();
  return string(cstr, escapedlen-1);
#else
  string result;
  result.reserve(len);
  for (size_t i=0; i<len; ++i)
  {
    if (bin[i] & 0x80)
    {
      char buf[8];
      sprintf(buf, "\\\\%03o", unsigned(bin[i]));
      result += buf;
    }
    else switch (bin[i])
    {
    case 0:
      result += "\\\\000";
      break;

    case '\'':
      result += "\\'";
      break;

    case '\\':
      result += "\\\\\\\\";
      break;

    default:
      result += char(bin[i]);
    }
  }
  return result;
#endif
}

string pqxx::escape_binary(const unsigned char bin[])
{
  return escape_binary(bin, strlen(reinterpret_cast<const char *>(bin)));
}

string pqxx::escape_binary(const char bin[], size_t len)
{
  return escape_binary(reinterpret_cast<const unsigned char *>(bin), len);
}

string pqxx::escape_binary(const char bin[])
{
  return escape_binary(bin, strlen(bin));
}

string pqxx::escape_binary(const string &bin)
{
  return escape_binary(bin.c_str(), bin.size());
}

<|endoftext|>