<commit_before>/* libwpd
 * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
 * Copyright (C) 2007 Fridrich Strba (fridrich.strba@bluewin.ch)
 * Copyright (C) 2007 Novell, Inc. (http://www.novell.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02111-1301 USA
 *
 * For further information visit http://libwpd.sourceforge.net
 */

#include "WPXStreamImplementation.h"
#include "WPXOLEStream.h"

#include <fstream>
#include <sstream>
#include <string>
#include <limits>

using namespace libwpd;

class WPXFileStreamPrivate
{
public:
	WPXFileStreamPrivate();
	~WPXFileStreamPrivate();
	std::fstream file;
	std::stringstream buffer;
	unsigned long streamSize;
	unsigned char *buf;
	unsigned char *readBuffer;
	unsigned long readBufferLength;
	unsigned long readBufferPos;
private:
	WPXFileStreamPrivate(const WPXFileStreamPrivate&);
	WPXFileStreamPrivate& operator=(const WPXFileStreamPrivate&);
};

class WPXStringStreamPrivate
{
public:
	WPXStringStreamPrivate(const std::string str);
	~WPXStringStreamPrivate();
	std::stringstream buffer;
	unsigned long streamSize;
	unsigned char *buf;
private:
	WPXStringStreamPrivate(const WPXStringStreamPrivate&);
	WPXStringStreamPrivate& operator=(const WPXStringStreamPrivate&);
};

WPXFileStreamPrivate::WPXFileStreamPrivate() :
	file(),
	buffer(std::ios::binary | std::ios::in | std::ios::out),
	streamSize(0),
	buf(0),
	readBuffer(0),
	readBufferLength(0),
	readBufferPos(0)
{
}

WPXFileStreamPrivate::~WPXFileStreamPrivate()
{
	if (buf)
		delete [] buf;
	if (readBuffer)
		delete [] readBuffer;
}

WPXStringStreamPrivate::WPXStringStreamPrivate(const std::string str) :
	buffer(str, std::ios::binary | std::ios::in),
	streamSize(0),
	buf(0)
{
}

WPXStringStreamPrivate::~WPXStringStreamPrivate()
{
	if (buf)
		delete [] buf;
}

WPXFileStream::WPXFileStream(const char* filename) :
	WPXInputStream(),
	d(new WPXFileStreamPrivate)
{
	d->file.open( filename, std::ios::binary | std::ios::in );
	d->file.seekg( 0, std::ios::end );
	d->streamSize = (d->file.good() ? (unsigned long)d->file.tellg() : (unsigned long)-1L);
	if (d->streamSize == (unsigned long)-1) // tellg() returned ERROR
		d->streamSize = 0;
	 // preventing possible unsigned/signed issues later by truncating the file
	if (d->streamSize > (std::numeric_limits<unsigned long>::max)() / 2)
		d->streamSize = (std::numeric_limits<unsigned long>::max)() / 2;
	d->file.seekg( 0, std::ios::beg );
}

WPXFileStream::~WPXFileStream()
{
	delete d;
}

#define BUFFER_MAX 65536

const unsigned char *WPXFileStream::read(unsigned long numBytes, unsigned long &numBytesRead)
{
	numBytesRead = 0;

	if (numBytes == 0 || /* atEOS() || */ numBytes > (std::numeric_limits<unsigned long>::max)()/2
		|| !d->file.good())
		return 0;

	// can we read from the buffer?
	if (d->readBuffer && (d->readBufferPos + numBytes > d->readBufferPos)
		&& (d->readBufferPos + numBytes <= d->readBufferLength))
	{
		const unsigned char *pTmp = d->readBuffer + d->readBufferPos;
		d->readBufferPos += numBytes;
		numBytesRead = numBytes;
		return pTmp;
	}

	// hmm, we cannot: go back by the bytes we read ahead && invalidate the buffer
	if (d->readBuffer)
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	unsigned long curpos = tell();
	if (curpos == (unsigned long)-1)  // tellg() returned ERROR
		return 0;

	if ( (curpos + numBytes < curpos) /*overflow*/ ||
		(curpos + numBytes >= d->streamSize) ) /*reading more than available*/
	{
		numBytes = d->streamSize - curpos;
	}

	if (numBytes < BUFFER_MAX)
	{
		if (BUFFER_MAX < d->streamSize - curpos)
			d->readBufferLength = BUFFER_MAX;
		else /* BUFFER_MAX >= d->streamSize - curpos */
			d->readBufferLength = d->streamSize - curpos;
	}
	else
		d->readBufferLength = numBytes;

	d->file.seekg(d->readBufferLength, std::ios::cur);
	d->file.seekg(curpos, std::ios::beg);

	d->readBuffer = new unsigned char[d->readBufferLength];
	d->file.read((char *)(d->readBuffer), d->readBufferLength);

	if (!d->file.good())
		d->file.clear();
	d->readBufferPos = 0;
	if (d->readBufferLength == 0)
		return 0;

	numBytesRead = numBytes;

	d->readBufferPos += numBytesRead;
	return const_cast<const unsigned char*>( d->readBuffer );
}

long WPXFileStream::tell()
{
	return d->file.good() ? (long)((long)d->file.tellg() - d->readBufferLength + d->readBufferPos) : -1L;
}

int WPXFileStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
	if (seekType == WPX_SEEK_CUR)
		offset += tell();

	if (offset < 0)
		offset = 0;
	if (offset > (long)d->streamSize)
		offset = (long)d->streamSize;

	if (d->file.good() && offset < d->file.tellg() && (unsigned long)offset >= (unsigned long)d->file.tellg() - d->readBufferLength)
	{
		d->readBufferPos = offset + d->readBufferLength - d->file.tellg();
		return 0;
	}

	if (d->readBuffer) // seeking outside of the buffer, so invalidate the buffer
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	if(d->file.good())
	{
		d->file.seekg(offset, std::ios::beg);
		return (int) ((long)d->file.tellg() == -1) ;
	}
	else
		return -1;
}

bool WPXFileStream::atEOS()
{
	return (tell() >= (long)d->streamSize);
}

bool WPXFileStream::isOLEStream()
{
	if (!d->file.good())
		return false;

	if (d->readBuffer)
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	if (d->buffer.str().empty())
		d->buffer << d->file.rdbuf();
	Storage tmpStorage( d->buffer );
	seek(0, WPX_SEEK_SET);
	if (tmpStorage.isOLEStream())
		return true;
	return false;
}

WPXInputStream* WPXFileStream::getDocumentOLEStream(const char * name)
{
	if (!d->file.good())
		return (WPXInputStream*)0;

	if (d->readBuffer)
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	if (d->buffer.str().empty())
		d->buffer << d->file.rdbuf();
	Storage *tmpStorage = new Storage( d->buffer );
	Stream tmpStream( tmpStorage, name );
	if (!tmpStorage || (tmpStorage->result() != Storage::Ok)  || !tmpStream.size())
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	if (d->buf)
		delete [] d->buf;
	d->buf = new unsigned char[tmpStream.size()];

	unsigned long tmpLength;
	tmpLength = tmpStream.read((unsigned char *)(d->buf), tmpStream.size());

	// sanity check
	if (tmpLength > tmpStream.size() || tmpLength < tmpStream.size())
	/* something went wrong here and we do not trust the
	   resulting buffer */
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	delete tmpStorage;
	return new WPXStringStream((d->buf), tmpLength);
}

WPXStringStream::WPXStringStream(const unsigned char *data, const unsigned int dataSize) :
	WPXInputStream(),
	d(new WPXStringStreamPrivate(std::string((const char *)data, dataSize)))
{
	d->buffer.seekg( 0, std::ios::end );
	d->streamSize = (d->buffer.good() ? (unsigned long)d->buffer.tellg() : (unsigned long)-1L);
	if (d->streamSize == (unsigned long)-1)
		d->streamSize = 0;
	 // preventing possible unsigned/signed issues later by truncating the file
	if (d->streamSize > (std::numeric_limits<unsigned long>::max)() / 2)
		d->streamSize = (std::numeric_limits<unsigned long>::max)() / 2;
	d->buffer.seekg( 0, std::ios::beg );
}

WPXStringStream::~WPXStringStream()
{
	delete d;
}

const unsigned char *WPXStringStream::read(unsigned long numBytes, unsigned long &numBytesRead)
{
	numBytesRead = 0;

	if (numBytes == 0)
		return 0;

	if (atEOS() || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
		return 0;

	unsigned long curpos = d->buffer.tellg();
	if (curpos == (unsigned long)-1) //tellg() returned ERROR
		return 0;

	if ( (curpos + numBytes < curpos) /*overflow*/ ||
		(curpos + numBytes > d->streamSize) ) /*reading more than available*/
	{
		numBytes = d->streamSize - curpos;
	}

	if (d->buf)
		delete [] d->buf;
	d->buf = new unsigned char[numBytes];

	if(d->buffer.good())
	{
		d->buffer.read((char *)(d->buf), numBytes);
		numBytesRead = (long)d->buffer.tellg() - curpos;
	}

	return d->buf;
}

long WPXStringStream::tell()
{
	return d->buffer.good() ? (long)d->buffer.tellg() : -1L;
}

int WPXStringStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
	if (seekType == WPX_SEEK_SET)
	{
		if (offset < 0)
			offset = 0;
		if (offset > (long)d->streamSize)
			offset = d->streamSize;
	}

	if (seekType == WPX_SEEK_CUR)
	{
		if (tell() + offset < 0)
			offset = -tell();
		if (tell() + offset > (long)d->streamSize)
			offset = d->streamSize - tell();
	}

	if(d->buffer.good())
	{
		d->buffer.seekg(offset, ((seekType == WPX_SEEK_SET) ? std::ios::beg : std::ios::cur));
		return (int) ( (long)d->buffer.tellg() == -1);
	}
	else
		return -1;
}

bool WPXStringStream::atEOS()
{
	return (d->buffer.tellg() >= (long)d->streamSize);
}

bool WPXStringStream::isOLEStream()
{
	if (!d->buffer.good())
		return false;

	Storage tmpStorage( d->buffer );
	if (tmpStorage.isOLEStream())
	{
		seek(0, WPX_SEEK_SET);
		return true;
	}
	seek(0, WPX_SEEK_SET);
	return false;
}

WPXInputStream* WPXStringStream::getDocumentOLEStream(const char * name)
{
	if (!d->buffer.good())
		return false;

	Storage *tmpStorage = new Storage( d->buffer );
	Stream tmpStream( tmpStorage, name );
	if (!tmpStorage || (tmpStorage->result() != Storage::Ok)  || !tmpStream.size())
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	if (d->buf)
		delete [] d->buf;
	d->buf = new unsigned char[tmpStream.size()];
	unsigned long tmpLength;
	tmpLength = tmpStream.read((unsigned char *)(d->buf), tmpStream.size());

	// sanity check
	if (tmpLength > tmpStream.size() || tmpLength < tmpStream.size())
	/* something went wrong here and we do not trust the
	   resulting buffer */
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	delete tmpStorage;
	return new WPXStringStream(d->buf, tmpLength);
}
<commit_msg>fix bug#13127: return null pointer instead of "false"<commit_after>/* libwpd
 * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
 * Copyright (C) 2007 Fridrich Strba (fridrich.strba@bluewin.ch)
 * Copyright (C) 2007 Novell, Inc. (http://www.novell.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02111-1301 USA
 *
 * For further information visit http://libwpd.sourceforge.net
 */

#include "WPXStreamImplementation.h"
#include "WPXOLEStream.h"

#include <fstream>
#include <sstream>
#include <string>
#include <limits>

using namespace libwpd;

class WPXFileStreamPrivate
{
public:
	WPXFileStreamPrivate();
	~WPXFileStreamPrivate();
	std::fstream file;
	std::stringstream buffer;
	unsigned long streamSize;
	unsigned char *buf;
	unsigned char *readBuffer;
	unsigned long readBufferLength;
	unsigned long readBufferPos;
private:
	WPXFileStreamPrivate(const WPXFileStreamPrivate&);
	WPXFileStreamPrivate& operator=(const WPXFileStreamPrivate&);
};

class WPXStringStreamPrivate
{
public:
	WPXStringStreamPrivate(const std::string str);
	~WPXStringStreamPrivate();
	std::stringstream buffer;
	unsigned long streamSize;
	unsigned char *buf;
private:
	WPXStringStreamPrivate(const WPXStringStreamPrivate&);
	WPXStringStreamPrivate& operator=(const WPXStringStreamPrivate&);
};

WPXFileStreamPrivate::WPXFileStreamPrivate() :
	file(),
	buffer(std::ios::binary | std::ios::in | std::ios::out),
	streamSize(0),
	buf(0),
	readBuffer(0),
	readBufferLength(0),
	readBufferPos(0)
{
}

WPXFileStreamPrivate::~WPXFileStreamPrivate()
{
	if (buf)
		delete [] buf;
	if (readBuffer)
		delete [] readBuffer;
}

WPXStringStreamPrivate::WPXStringStreamPrivate(const std::string str) :
	buffer(str, std::ios::binary | std::ios::in),
	streamSize(0),
	buf(0)
{
}

WPXStringStreamPrivate::~WPXStringStreamPrivate()
{
	if (buf)
		delete [] buf;
}

WPXFileStream::WPXFileStream(const char* filename) :
	WPXInputStream(),
	d(new WPXFileStreamPrivate)
{
	d->file.open( filename, std::ios::binary | std::ios::in );
	d->file.seekg( 0, std::ios::end );
	d->streamSize = (d->file.good() ? (unsigned long)d->file.tellg() : (unsigned long)-1L);
	if (d->streamSize == (unsigned long)-1) // tellg() returned ERROR
		d->streamSize = 0;
	 // preventing possible unsigned/signed issues later by truncating the file
	if (d->streamSize > (std::numeric_limits<unsigned long>::max)() / 2)
		d->streamSize = (std::numeric_limits<unsigned long>::max)() / 2;
	d->file.seekg( 0, std::ios::beg );
}

WPXFileStream::~WPXFileStream()
{
	delete d;
}

#define BUFFER_MAX 65536

const unsigned char *WPXFileStream::read(unsigned long numBytes, unsigned long &numBytesRead)
{
	numBytesRead = 0;

	if (numBytes == 0 || /* atEOS() || */ numBytes > (std::numeric_limits<unsigned long>::max)()/2
		|| !d->file.good())
		return 0;

	// can we read from the buffer?
	if (d->readBuffer && (d->readBufferPos + numBytes > d->readBufferPos)
		&& (d->readBufferPos + numBytes <= d->readBufferLength))
	{
		const unsigned char *pTmp = d->readBuffer + d->readBufferPos;
		d->readBufferPos += numBytes;
		numBytesRead = numBytes;
		return pTmp;
	}

	// hmm, we cannot: go back by the bytes we read ahead && invalidate the buffer
	if (d->readBuffer)
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	unsigned long curpos = tell();
	if (curpos == (unsigned long)-1)  // tellg() returned ERROR
		return 0;

	if ( (curpos + numBytes < curpos) /*overflow*/ ||
		(curpos + numBytes >= d->streamSize) ) /*reading more than available*/
	{
		numBytes = d->streamSize - curpos;
	}

	if (numBytes < BUFFER_MAX)
	{
		if (BUFFER_MAX < d->streamSize - curpos)
			d->readBufferLength = BUFFER_MAX;
		else /* BUFFER_MAX >= d->streamSize - curpos */
			d->readBufferLength = d->streamSize - curpos;
	}
	else
		d->readBufferLength = numBytes;

	d->file.seekg(d->readBufferLength, std::ios::cur);
	d->file.seekg(curpos, std::ios::beg);

	d->readBuffer = new unsigned char[d->readBufferLength];
	d->file.read((char *)(d->readBuffer), d->readBufferLength);

	if (!d->file.good())
		d->file.clear();
	d->readBufferPos = 0;
	if (d->readBufferLength == 0)
		return 0;

	numBytesRead = numBytes;

	d->readBufferPos += numBytesRead;
	return const_cast<const unsigned char*>( d->readBuffer );
}

long WPXFileStream::tell()
{
	return d->file.good() ? (long)((long)d->file.tellg() - d->readBufferLength + d->readBufferPos) : -1L;
}

int WPXFileStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
	if (seekType == WPX_SEEK_CUR)
		offset += tell();

	if (offset < 0)
		offset = 0;
	if (offset > (long)d->streamSize)
		offset = (long)d->streamSize;

	if (d->file.good() && offset < d->file.tellg() && (unsigned long)offset >= (unsigned long)d->file.tellg() - d->readBufferLength)
	{
		d->readBufferPos = offset + d->readBufferLength - d->file.tellg();
		return 0;
	}

	if (d->readBuffer) // seeking outside of the buffer, so invalidate the buffer
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	if(d->file.good())
	{
		d->file.seekg(offset, std::ios::beg);
		return (int) ((long)d->file.tellg() == -1) ;
	}
	else
		return -1;
}

bool WPXFileStream::atEOS()
{
	return (tell() >= (long)d->streamSize);
}

bool WPXFileStream::isOLEStream()
{
	if (!d->file.good())
		return false;

	if (d->readBuffer)
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	if (d->buffer.str().empty())
		d->buffer << d->file.rdbuf();
	Storage tmpStorage( d->buffer );
	seek(0, WPX_SEEK_SET);
	if (tmpStorage.isOLEStream())
		return true;
	return false;
}

WPXInputStream* WPXFileStream::getDocumentOLEStream(const char * name)
{
	if (!d->file.good())
		return (WPXInputStream*)0;

	if (d->readBuffer)
	{
		d->file.seekg((unsigned long)d->file.tellg() - d->readBufferLength, std::ios::beg);
		d->file.seekg(d->readBufferPos, std::ios::cur);
		delete [] d->readBuffer;
		d->readBuffer = 0; d->readBufferPos = 0; d->readBufferLength = 0;
	}

	if (d->buffer.str().empty())
		d->buffer << d->file.rdbuf();
	Storage *tmpStorage = new Storage( d->buffer );
	Stream tmpStream( tmpStorage, name );
	if (!tmpStorage || (tmpStorage->result() != Storage::Ok)  || !tmpStream.size())
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	if (d->buf)
		delete [] d->buf;
	d->buf = new unsigned char[tmpStream.size()];

	unsigned long tmpLength;
	tmpLength = tmpStream.read((unsigned char *)(d->buf), tmpStream.size());

	// sanity check
	if (tmpLength > tmpStream.size() || tmpLength < tmpStream.size())
	/* something went wrong here and we do not trust the
	   resulting buffer */
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	delete tmpStorage;
	return new WPXStringStream((d->buf), tmpLength);
}

WPXStringStream::WPXStringStream(const unsigned char *data, const unsigned int dataSize) :
	WPXInputStream(),
	d(new WPXStringStreamPrivate(std::string((const char *)data, dataSize)))
{
	d->buffer.seekg( 0, std::ios::end );
	d->streamSize = (d->buffer.good() ? (unsigned long)d->buffer.tellg() : (unsigned long)-1L);
	if (d->streamSize == (unsigned long)-1)
		d->streamSize = 0;
	 // preventing possible unsigned/signed issues later by truncating the file
	if (d->streamSize > (std::numeric_limits<unsigned long>::max)() / 2)
		d->streamSize = (std::numeric_limits<unsigned long>::max)() / 2;
	d->buffer.seekg( 0, std::ios::beg );
}

WPXStringStream::~WPXStringStream()
{
	delete d;
}

const unsigned char *WPXStringStream::read(unsigned long numBytes, unsigned long &numBytesRead)
{
	numBytesRead = 0;

	if (numBytes == 0)
		return 0;

	if (atEOS() || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
		return 0;

	unsigned long curpos = d->buffer.tellg();
	if (curpos == (unsigned long)-1) //tellg() returned ERROR
		return 0;

	if ( (curpos + numBytes < curpos) /*overflow*/ ||
		(curpos + numBytes > d->streamSize) ) /*reading more than available*/
	{
		numBytes = d->streamSize - curpos;
	}

	if (d->buf)
		delete [] d->buf;
	d->buf = new unsigned char[numBytes];

	if(d->buffer.good())
	{
		d->buffer.read((char *)(d->buf), numBytes);
		numBytesRead = (long)d->buffer.tellg() - curpos;
	}

	return d->buf;
}

long WPXStringStream::tell()
{
	return d->buffer.good() ? (long)d->buffer.tellg() : -1L;
}

int WPXStringStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
	if (seekType == WPX_SEEK_SET)
	{
		if (offset < 0)
			offset = 0;
		if (offset > (long)d->streamSize)
			offset = d->streamSize;
	}

	if (seekType == WPX_SEEK_CUR)
	{
		if (tell() + offset < 0)
			offset = -tell();
		if (tell() + offset > (long)d->streamSize)
			offset = d->streamSize - tell();
	}

	if(d->buffer.good())
	{
		d->buffer.seekg(offset, ((seekType == WPX_SEEK_SET) ? std::ios::beg : std::ios::cur));
		return (int) ( (long)d->buffer.tellg() == -1);
	}
	else
		return -1;
}

bool WPXStringStream::atEOS()
{
	return (d->buffer.tellg() >= (long)d->streamSize);
}

bool WPXStringStream::isOLEStream()
{
	if (!d->buffer.good())
		return false;

	Storage tmpStorage( d->buffer );
	if (tmpStorage.isOLEStream())
	{
		seek(0, WPX_SEEK_SET);
		return true;
	}
	seek(0, WPX_SEEK_SET);
	return false;
}

WPXInputStream* WPXStringStream::getDocumentOLEStream(const char * name)
{
	if (!d->buffer.good())
		return NULL;

	Storage *tmpStorage = new Storage( d->buffer );
	Stream tmpStream( tmpStorage, name );
	if (!tmpStorage || (tmpStorage->result() != Storage::Ok)  || !tmpStream.size())
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	if (d->buf)
		delete [] d->buf;
	d->buf = new unsigned char[tmpStream.size()];
	unsigned long tmpLength;
	tmpLength = tmpStream.read((unsigned char *)(d->buf), tmpStream.size());

	// sanity check
	if (tmpLength > tmpStream.size() || tmpLength < tmpStream.size())
	/* something went wrong here and we do not trust the
	   resulting buffer */
	{
		if (tmpStorage)
			delete tmpStorage;
		return (WPXInputStream*)0;
	}

	delete tmpStorage;
	return new WPXStringStream(d->buf, tmpLength);
}
<|endoftext|>


<commit_before>#pragma once

#include <map>
#include <memory>
#include <string>

#include "table.hpp"

namespace opossum {

class StorageManager {
 public:
  static StorageManager &get();

  void add_table(const std::string &name, std::shared_ptr<Table> tp);
  void drop_table(const std::string &name);
  std::shared_ptr<Table> get_table(const std::string &name) const;
  void print(std::ostream &out = std::cout) const;

 protected:
  StorageManager() {}
  StorageManager(StorageManager const &) = delete;
  StorageManager(StorageManager &&) = delete;

  std::map<std::string, std::shared_ptr<Table>> _tables;
};
}  // namespace opossum
<commit_msg>Add TODO to storage_manager about ctor consistency<commit_after>#pragma once

#include <map>
#include <memory>
#include <string>

#include "table.hpp"

namespace opossum {

class StorageManager {
 public:
  static StorageManager &get();

  void add_table(const std::string &name, std::shared_ptr<Table> tp);
  void drop_table(const std::string &name);
  std::shared_ptr<Table> get_table(const std::string &name) const;
  void print(std::ostream &out = std::cout) const;

 protected:
  StorageManager() {}
  StorageManager(StorageManager const &) = delete;
  StorageManager(StorageManager &&) = delete;
  // TODO(anyone): deleted/default ctors/dtors should be under consistent visibility rules everywhere

  std::map<std::string, std::shared_ptr<Table>> _tables;
};
}  // namespace opossum
<|endoftext|>


<commit_before>#include "httpclient.h"
#include "utilities/utils.h"

#include <assert.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/opensslv.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>

#include "crypto/openssl_compat.h"

struct WriteStringArg {
  std::string out;
  int64_t limit{0};
};

/*****************************************************************************/
/**
 * \par Description:
 *    A writeback handler for the curl library. It handles writing response
 *    data from curl into a string.
 *    https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
 *
 */
static size_t writeString(void* contents, size_t size, size_t nmemb, void* userp) {
  assert(contents);
  assert(userp);
  // append the writeback data to the provided string
  auto* arg = static_cast<WriteStringArg*>(userp);
  if (arg->limit > 0) {
    if (arg->out.length() + size * nmemb > static_cast<uint64_t>(arg->limit)) {
      return 0;
    }
  }
  (static_cast<WriteStringArg*>(userp))->out.append(static_cast<char*>(contents), size * nmemb);

  // return size of written data
  return size * nmemb;
}

HttpClient::HttpClient() : user_agent(std::string("Aktualizr/") + AKTUALIZR_VERSION) {
  curl = curl_easy_init();
  headers = nullptr;
  http_code = 0;

  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60L);

  // let curl use our write function
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeString);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

  curl_easy_setopt(curl, CURLOPT_VERBOSE, get_curlopt_verbose());

  headers = curl_slist_append(headers, "Content-Type: application/json");
  headers = curl_slist_append(headers, "Accept: */*");
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
}

HttpClient::HttpClient(const HttpClient& curl_in) : pkcs11_key(curl_in.pkcs11_key), pkcs11_cert(curl_in.pkcs11_key) {
  curl = curl_easy_duphandle(curl_in.curl);

  struct curl_slist* inlist = curl_in.headers;
  headers = nullptr;
  struct curl_slist* tmp;

  while (inlist != nullptr) {
    tmp = curl_slist_append(headers, inlist->data);

    if (tmp == nullptr) {
      curl_slist_free_all(headers);
      throw std::runtime_error("curl_slist_append returned null");
    }

    headers = tmp;
    inlist = inlist->next;
  }
}

CurlGlobalInitWrapper HttpClient::manageCurlGlobalInit_{};

HttpClient::~HttpClient() {
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
}

HttpResponse HttpClient::get(const std::string& url, int64_t maxsize) {
  CURL* curl_get = curl_easy_duphandle(curl);
  // Clear POSTFIELDS to remove any lingering references to strings that have
  // probably since been deallocated.
  curl_easy_setopt(curl_get, CURLOPT_POSTFIELDS, "");
  curl_easy_setopt(curl_get, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl_get, CURLOPT_HTTPGET, 1L);
  if (maxsize >= 0) {
    // it will only take effect if the server declares the size in advance,
    //    writeString callback takes care of the other case
    curl_easy_setopt(curl_get, CURLOPT_MAXFILESIZE_LARGE, maxsize);
  }
  curl_easy_setopt(curl_get, CURLOPT_LOW_SPEED_TIME, speed_limit_time_interval_);
  curl_easy_setopt(curl_get, CURLOPT_LOW_SPEED_LIMIT, speed_limit_bytes_per_sec_);
  LOG_DEBUG << "GET " << url;
  HttpResponse response = perform(curl_get, RETRY_TIMES, maxsize);
  curl_easy_cleanup(curl_get);
  return response;
}

void HttpClient::setCerts(const std::string& ca, CryptoSource ca_source, const std::string& cert,
                          CryptoSource cert_source, const std::string& pkey, CryptoSource pkey_source) {
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);

  if (ca_source == CryptoSource::kPkcs11) {
    throw std::runtime_error("Accessing CA certificate on PKCS11 devices isn't currently supported");
  }
  std::unique_ptr<TemporaryFile> tmp_ca_file = std_::make_unique<TemporaryFile>("tls-ca");
  tmp_ca_file->PutContents(ca);
  curl_easy_setopt(curl, CURLOPT_CAINFO, tmp_ca_file->Path().c_str());
  tls_ca_file = std::move_if_noexcept(tmp_ca_file);

  if (cert_source == CryptoSource::kPkcs11) {
    curl_easy_setopt(curl, CURLOPT_SSLCERT, cert.c_str());
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "ENG");
  } else {  // cert_source == CryptoSource::kFile
    std::unique_ptr<TemporaryFile> tmp_cert_file = std_::make_unique<TemporaryFile>("tls-cert");
    tmp_cert_file->PutContents(cert);
    curl_easy_setopt(curl, CURLOPT_SSLCERT, tmp_cert_file->Path().c_str());
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
    tls_cert_file = std::move_if_noexcept(tmp_cert_file);
  }
  pkcs11_cert = (cert_source == CryptoSource::kPkcs11);

  if (pkey_source == CryptoSource::kPkcs11) {
    curl_easy_setopt(curl, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
    curl_easy_setopt(curl, CURLOPT_SSLKEY, pkey.c_str());
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "ENG");
  } else {  // pkey_source == CryptoSource::kFile
    std::unique_ptr<TemporaryFile> tmp_pkey_file = std_::make_unique<TemporaryFile>("tls-pkey");
    tmp_pkey_file->PutContents(pkey);
    curl_easy_setopt(curl, CURLOPT_SSLKEY, tmp_pkey_file->Path().c_str());
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    tls_pkey_file = std::move_if_noexcept(tmp_pkey_file);
  }
  pkcs11_key = (pkey_source == CryptoSource::kPkcs11);
}

HttpResponse HttpClient::post(const std::string& url, const Json::Value& data) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_POST, 1);
  std::string data_str = Json::FastWriter().write(data);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data_str.c_str());
  LOG_TRACE << "post request body:" << data;
  return perform(curl, RETRY_TIMES, HttpInterface::kPostRespLimit);
}

HttpResponse HttpClient::put(const std::string& url, const Json::Value& data) {
  CURL* curl_put = curl_easy_duphandle(curl);

  // TODO: it is a workaround for an unidentified bug in libcurl. Ideally the bug itself should be fixed.
  if (pkcs11_key) {
    curl_easy_setopt(curl_put, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl_put, CURLOPT_SSLKEYTYPE, "ENG");
  }

  if (pkcs11_cert) {
    curl_easy_setopt(curl_put, CURLOPT_SSLCERTTYPE, "ENG");
  }

  curl_easy_setopt(curl_put, CURLOPT_URL, url.c_str());
  std::string data_str = Json::FastWriter().write(data);
  curl_easy_setopt(curl_put, CURLOPT_POSTFIELDS, data_str.c_str());
  curl_easy_setopt(curl_put, CURLOPT_CUSTOMREQUEST, "PUT");
  LOG_TRACE << "put request body:" << data;
  HttpResponse result = perform(curl_put, RETRY_TIMES, HttpInterface::kPutRespLimit);
  curl_easy_cleanup(curl_put);
  return result;
}

HttpResponse HttpClient::perform(CURL* curl_handler, int retry_times, int64_t size_limit) {
  WriteStringArg response_arg;
  response_arg.limit = size_limit;
  curl_easy_setopt(curl_handler, CURLOPT_WRITEDATA, (void*)&response_arg);
  CURLcode result = curl_easy_perform(curl_handler);
  curl_easy_getinfo(curl_handler, CURLINFO_RESPONSE_CODE, &http_code);
  HttpResponse response(response_arg.out, http_code, result, (result != CURLE_OK) ? curl_easy_strerror(result) : "");
  if (response.curl_code != CURLE_OK || response.http_status_code >= 500) {
    std::ostringstream error_message;
    error_message << "curl error " << response.curl_code << " (http code " << response.http_status_code
                  << "): " << response.error_message;
    LOG_ERROR << error_message.str();
    if (retry_times != 0) {
      sleep(1);
      response = perform(curl_handler, --retry_times, size_limit);
    }
  }
  LOG_TRACE << "response: " << response.body;
  return response;
}

HttpResponse HttpClient::download(const std::string& url, curl_write_callback callback, void* userp) {
  CURL* curl_download = curl_easy_duphandle(curl);

  // TODO: it is a workaround for an unidentified bug in libcurl. Ideally the bug itself should be fixed.
  if (pkcs11_key) {
    curl_easy_setopt(curl_download, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl_download, CURLOPT_SSLKEYTYPE, "ENG");
  }

  if (pkcs11_cert) {
    curl_easy_setopt(curl_download, CURLOPT_SSLCERTTYPE, "ENG");
  }

  curl_easy_setopt(curl_download, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl_download, CURLOPT_HTTPGET, 1L);
  curl_easy_setopt(curl_download, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl_download, CURLOPT_WRITEFUNCTION, callback);
  curl_easy_setopt(curl_download, CURLOPT_WRITEDATA, userp);
  curl_easy_setopt(curl_download, CURLOPT_LOW_SPEED_TIME, speed_limit_time_interval_);
  curl_easy_setopt(curl_download, CURLOPT_LOW_SPEED_LIMIT, speed_limit_bytes_per_sec_);

  CURLcode result = curl_easy_perform(curl_download);
  curl_easy_getinfo(curl_download, CURLINFO_RESPONSE_CODE, &http_code);
  HttpResponse response("", http_code, result, (result != CURLE_OK) ? curl_easy_strerror(result) : "");
  curl_easy_cleanup(curl_download);
  return response;
}

// vim: set tabstop=2 shiftwidth=2 expandtab:
<commit_msg>Apply curl bug workaround for GET requests<commit_after>#include "httpclient.h"
#include "utilities/utils.h"

#include <assert.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/opensslv.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>

#include "crypto/openssl_compat.h"

struct WriteStringArg {
  std::string out;
  int64_t limit{0};
};

/*****************************************************************************/
/**
 * \par Description:
 *    A writeback handler for the curl library. It handles writing response
 *    data from curl into a string.
 *    https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
 *
 */
static size_t writeString(void* contents, size_t size, size_t nmemb, void* userp) {
  assert(contents);
  assert(userp);
  // append the writeback data to the provided string
  auto* arg = static_cast<WriteStringArg*>(userp);
  if (arg->limit > 0) {
    if (arg->out.length() + size * nmemb > static_cast<uint64_t>(arg->limit)) {
      return 0;
    }
  }
  (static_cast<WriteStringArg*>(userp))->out.append(static_cast<char*>(contents), size * nmemb);

  // return size of written data
  return size * nmemb;
}

HttpClient::HttpClient() : user_agent(std::string("Aktualizr/") + AKTUALIZR_VERSION) {
  curl = curl_easy_init();
  headers = nullptr;
  http_code = 0;

  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60L);

  // let curl use our write function
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeString);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

  curl_easy_setopt(curl, CURLOPT_VERBOSE, get_curlopt_verbose());

  headers = curl_slist_append(headers, "Content-Type: application/json");
  headers = curl_slist_append(headers, "Accept: */*");
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
}

HttpClient::HttpClient(const HttpClient& curl_in) : pkcs11_key(curl_in.pkcs11_key), pkcs11_cert(curl_in.pkcs11_key) {
  curl = curl_easy_duphandle(curl_in.curl);

  struct curl_slist* inlist = curl_in.headers;
  headers = nullptr;
  struct curl_slist* tmp;

  while (inlist != nullptr) {
    tmp = curl_slist_append(headers, inlist->data);

    if (tmp == nullptr) {
      curl_slist_free_all(headers);
      throw std::runtime_error("curl_slist_append returned null");
    }

    headers = tmp;
    inlist = inlist->next;
  }
}

CurlGlobalInitWrapper HttpClient::manageCurlGlobalInit_{};

HttpClient::~HttpClient() {
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
}

HttpResponse HttpClient::get(const std::string& url, int64_t maxsize) {
  CURL* curl_get = curl_easy_duphandle(curl);

  // TODO: it is a workaround for an unidentified bug in libcurl. Ideally the bug itself should be fixed.
  if (pkcs11_key) {
    curl_easy_setopt(curl_get, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl_get, CURLOPT_SSLKEYTYPE, "ENG");
  }

  if (pkcs11_cert) {
    curl_easy_setopt(curl_get, CURLOPT_SSLCERTTYPE, "ENG");
  }

  // Clear POSTFIELDS to remove any lingering references to strings that have
  // probably since been deallocated.
  curl_easy_setopt(curl_get, CURLOPT_POSTFIELDS, "");
  curl_easy_setopt(curl_get, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl_get, CURLOPT_HTTPGET, 1L);
  if (maxsize >= 0) {
    // it will only take effect if the server declares the size in advance,
    //    writeString callback takes care of the other case
    curl_easy_setopt(curl_get, CURLOPT_MAXFILESIZE_LARGE, maxsize);
  }
  curl_easy_setopt(curl_get, CURLOPT_LOW_SPEED_TIME, speed_limit_time_interval_);
  curl_easy_setopt(curl_get, CURLOPT_LOW_SPEED_LIMIT, speed_limit_bytes_per_sec_);
  LOG_DEBUG << "GET " << url;
  HttpResponse response = perform(curl_get, RETRY_TIMES, maxsize);
  curl_easy_cleanup(curl_get);
  return response;
}

void HttpClient::setCerts(const std::string& ca, CryptoSource ca_source, const std::string& cert,
                          CryptoSource cert_source, const std::string& pkey, CryptoSource pkey_source) {
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
  curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);

  if (ca_source == CryptoSource::kPkcs11) {
    throw std::runtime_error("Accessing CA certificate on PKCS11 devices isn't currently supported");
  }
  std::unique_ptr<TemporaryFile> tmp_ca_file = std_::make_unique<TemporaryFile>("tls-ca");
  tmp_ca_file->PutContents(ca);
  curl_easy_setopt(curl, CURLOPT_CAINFO, tmp_ca_file->Path().c_str());
  tls_ca_file = std::move_if_noexcept(tmp_ca_file);

  if (cert_source == CryptoSource::kPkcs11) {
    curl_easy_setopt(curl, CURLOPT_SSLCERT, cert.c_str());
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "ENG");
  } else {  // cert_source == CryptoSource::kFile
    std::unique_ptr<TemporaryFile> tmp_cert_file = std_::make_unique<TemporaryFile>("tls-cert");
    tmp_cert_file->PutContents(cert);
    curl_easy_setopt(curl, CURLOPT_SSLCERT, tmp_cert_file->Path().c_str());
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
    tls_cert_file = std::move_if_noexcept(tmp_cert_file);
  }
  pkcs11_cert = (cert_source == CryptoSource::kPkcs11);

  if (pkey_source == CryptoSource::kPkcs11) {
    curl_easy_setopt(curl, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
    curl_easy_setopt(curl, CURLOPT_SSLKEY, pkey.c_str());
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "ENG");
  } else {  // pkey_source == CryptoSource::kFile
    std::unique_ptr<TemporaryFile> tmp_pkey_file = std_::make_unique<TemporaryFile>("tls-pkey");
    tmp_pkey_file->PutContents(pkey);
    curl_easy_setopt(curl, CURLOPT_SSLKEY, tmp_pkey_file->Path().c_str());
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    tls_pkey_file = std::move_if_noexcept(tmp_pkey_file);
  }
  pkcs11_key = (pkey_source == CryptoSource::kPkcs11);
}

HttpResponse HttpClient::post(const std::string& url, const Json::Value& data) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_POST, 1);
  std::string data_str = Json::FastWriter().write(data);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data_str.c_str());
  LOG_TRACE << "post request body:" << data;
  return perform(curl, RETRY_TIMES, HttpInterface::kPostRespLimit);
}

HttpResponse HttpClient::put(const std::string& url, const Json::Value& data) {
  CURL* curl_put = curl_easy_duphandle(curl);

  // TODO: it is a workaround for an unidentified bug in libcurl. Ideally the bug itself should be fixed.
  if (pkcs11_key) {
    curl_easy_setopt(curl_put, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl_put, CURLOPT_SSLKEYTYPE, "ENG");
  }

  if (pkcs11_cert) {
    curl_easy_setopt(curl_put, CURLOPT_SSLCERTTYPE, "ENG");
  }

  curl_easy_setopt(curl_put, CURLOPT_URL, url.c_str());
  std::string data_str = Json::FastWriter().write(data);
  curl_easy_setopt(curl_put, CURLOPT_POSTFIELDS, data_str.c_str());
  curl_easy_setopt(curl_put, CURLOPT_CUSTOMREQUEST, "PUT");
  LOG_TRACE << "put request body:" << data;
  HttpResponse result = perform(curl_put, RETRY_TIMES, HttpInterface::kPutRespLimit);
  curl_easy_cleanup(curl_put);
  return result;
}

HttpResponse HttpClient::perform(CURL* curl_handler, int retry_times, int64_t size_limit) {
  WriteStringArg response_arg;
  response_arg.limit = size_limit;
  curl_easy_setopt(curl_handler, CURLOPT_WRITEDATA, (void*)&response_arg);
  CURLcode result = curl_easy_perform(curl_handler);
  curl_easy_getinfo(curl_handler, CURLINFO_RESPONSE_CODE, &http_code);
  HttpResponse response(response_arg.out, http_code, result, (result != CURLE_OK) ? curl_easy_strerror(result) : "");
  if (response.curl_code != CURLE_OK || response.http_status_code >= 500) {
    std::ostringstream error_message;
    error_message << "curl error " << response.curl_code << " (http code " << response.http_status_code
                  << "): " << response.error_message;
    LOG_ERROR << error_message.str();
    if (retry_times != 0) {
      sleep(1);
      response = perform(curl_handler, --retry_times, size_limit);
    }
  }
  LOG_TRACE << "response: " << response.body;
  return response;
}

HttpResponse HttpClient::download(const std::string& url, curl_write_callback callback, void* userp) {
  CURL* curl_download = curl_easy_duphandle(curl);

  // TODO: it is a workaround for an unidentified bug in libcurl. Ideally the bug itself should be fixed.
  if (pkcs11_key) {
    curl_easy_setopt(curl_download, CURLOPT_SSLENGINE, "pkcs11");
    curl_easy_setopt(curl_download, CURLOPT_SSLKEYTYPE, "ENG");
  }

  if (pkcs11_cert) {
    curl_easy_setopt(curl_download, CURLOPT_SSLCERTTYPE, "ENG");
  }

  curl_easy_setopt(curl_download, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl_download, CURLOPT_HTTPGET, 1L);
  curl_easy_setopt(curl_download, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl_download, CURLOPT_WRITEFUNCTION, callback);
  curl_easy_setopt(curl_download, CURLOPT_WRITEDATA, userp);
  curl_easy_setopt(curl_download, CURLOPT_LOW_SPEED_TIME, speed_limit_time_interval_);
  curl_easy_setopt(curl_download, CURLOPT_LOW_SPEED_LIMIT, speed_limit_bytes_per_sec_);

  CURLcode result = curl_easy_perform(curl_download);
  curl_easy_getinfo(curl_download, CURLINFO_RESPONSE_CODE, &http_code);
  HttpResponse response("", http_code, result, (result != CURLE_OK) ? curl_easy_strerror(result) : "");
  curl_easy_cleanup(curl_download);
  return response;
}

// vim: set tabstop=2 shiftwidth=2 expandtab:
<|endoftext|>


<commit_before>/*
 *  This file is part of WinSparkle (http://winsparkle.org)
 *
 *  Copyright (C) 2009 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

// silence warnings in wxWidgets' CRT wrappers
#define _CRT_SECURE_NO_WARNINGS

#include "ui.h"

#define wxNO_NET_LIB
#define wxNO_XML_LIB
#define wxNO_XRC_LIB
#define wxNO_ADV_LIB
#define wxNO_HTML_LIB
#include <wx/setup.h>

#include <wx/app.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/gauge.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
#include <wx/timer.h>

#if !wxCHECK_VERSION(2,9,0)
#error "wxWidgets >= 2.9 is required to compile this code"
#endif

namespace winsparkle
{

/*--------------------------------------------------------------------------*
                       Window for communicating with the user
 *--------------------------------------------------------------------------*/

class UpdateDialog : public wxDialog
{
public:
    UpdateDialog();

    // changes state into "checking for updates"
    void StateCheckingUpdates();
    // change state into "no updates found"
    void StateNoUpdateFound();

private:
    void EnablePulsing(bool enable);
    void OnTimer(wxTimerEvent& event);
    void OnCloseButton(wxCommandEvent& event);
    void OnClose(wxCloseEvent& event);

private:
    wxTimer       m_timer;
    wxSizer      *m_infoSizer;
    wxSizer      *m_buttonSizer;
    wxStaticText *m_message;
    wxGauge      *m_progress;
    wxButton     *m_closeButton;
};

UpdateDialog::UpdateDialog()
    : wxDialog(NULL, wxID_ANY, _("Software Update"),
               wxDefaultPosition, wxDefaultSize,
               wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
      m_timer(this)
{
    SetIcons(wxICON(UpdateAvailable));

    wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);

    wxSizer *topSizer = new wxBoxSizer(wxHORIZONTAL);
    wxIcon bigIcon("UpdateAvailable", wxBITMAP_TYPE_ICO_RESOURCE, 48, 48);
    topSizer->Add
              (
                  new wxStaticBitmap(this, wxID_ANY, bigIcon),
                  wxSizerFlags(0).Border(wxALL, 10)
              );

    m_infoSizer = new wxBoxSizer(wxVERTICAL);
    topSizer->Add(m_infoSizer, wxSizerFlags(1).Expand().Border(wxALL, 10));

    m_message = new wxStaticText(this, wxID_ANY, "");
    m_infoSizer->Add(m_message, wxSizerFlags(0).Expand().Border(wxBOTTOM, 10));

    m_progress = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(300, 16));
    m_infoSizer->Add(m_progress, wxSizerFlags(0).Expand());

    m_buttonSizer = new wxBoxSizer(wxHORIZONTAL);
    m_closeButton = new wxButton(this, wxID_CANCEL);
    m_buttonSizer->Add(m_closeButton, wxSizerFlags(0).Border(wxLEFT));

    mainSizer->Add(topSizer, wxSizerFlags(1).Expand());
    mainSizer->Add
               (
                   m_buttonSizer,
                   wxSizerFlags(0).Right().Border(wxLEFT|wxRIGHT|wxBOTTOM, 10)
               );

    SetSizerAndFit(mainSizer);

    Bind(wxEVT_CLOSE_WINDOW, &UpdateDialog::OnClose, this);
    Bind(wxEVT_TIMER, &UpdateDialog::OnTimer, this);
    Bind(wxEVT_COMMAND_BUTTON_CLICKED, &UpdateDialog::OnCloseButton, this, wxID_CANCEL);
}

void UpdateDialog::EnablePulsing(bool enable)
{
    if ( enable && !m_timer.IsRunning() )
        m_timer.Start(100);
    else if ( !enable && m_timer.IsRunning() )
        m_timer.Stop();
}

void UpdateDialog::OnTimer(wxTimerEvent&)
{
    m_progress->Pulse();
}

void UpdateDialog::OnCloseButton(wxCommandEvent&)
{
    Close();
}

void UpdateDialog::OnClose(wxCloseEvent&)
{
    // We need to override this, because by default, wxDialog doesn't
    // destroy itself in Close().
    Destroy();
}

#define SHOW(c)    (c)->GetContainingSizer()->Show(c)
#define HIDE(c)    (c)->GetContainingSizer()->Hide(c)

void UpdateDialog::StateCheckingUpdates()
{
    m_message->SetLabel(_("Checking for updates..."));

    SHOW(m_progress);
    SHOW(m_closeButton);
    m_closeButton->SetLabel(_("Cancel"));
    EnablePulsing(true);
}

void UpdateDialog::StateNoUpdateFound()
{
    // FIXME: use Sparkle string -- "<version> is currently the newest version
    //        available..."
    m_message->SetLabel(_("No new updates are available."));

    HIDE(m_progress);
    m_closeButton->SetLabel(_("Close"));
    EnablePulsing(false);
}

/*--------------------------------------------------------------------------*
                             Inter-thread messages
 *--------------------------------------------------------------------------*/

// Terminate the wx thread
const int MSG_TERMINATE = wxNewId();

// Show "Checking for updates..." window
const int MSG_SHOW_CHECKING_UPDATES = wxNewId();

// Notify the UI that there were no updates
const int MSG_NO_UPDATE_FOUND = wxNewId();

/*--------------------------------------------------------------------------*
                                Application
 *--------------------------------------------------------------------------*/

class App : public wxApp
{
public:
    App();

    // Sends a message with ID @a msg to the app.
    void SendMsg(int msg);

private:
    void ShowWindow();

    void OnWindowClose(wxCloseEvent& event);
    void OnTerminate(wxThreadEvent& event);
    void OnShowCheckingUpdates(wxThreadEvent& event);
    void OnNoUpdateFound(wxThreadEvent& event);

private:
    UpdateDialog *m_win;
};

IMPLEMENT_APP_NO_MAIN(App)

App::App()
{
    m_win = NULL;

    // Keep the wx "main" thread running even without windows. This greatly
    // simplifies threads handling, because we don't have to correctly
    // implement wx-thread restarting.
    //
    // Note that this only works if we don't explicitly call ExitMainLoop(),
    // except in reaction to win_sparkle_cleanup()'s message.
    // win_sparkle_cleanup() relies on the availability of wxApp instance and
    // if the event loop terminated, wxEntry() would return and wxApp instance
    // would be destroyed.
    //
    // Also note that this is efficient, because if there are no windows, the
    // thread will sleep waiting for a new event. We could safe some memory
    // by shutting the thread down when it's no longer needed, though.
    SetExitOnFrameDelete(false);

    // Bind events to their handlers:
    Bind(wxEVT_COMMAND_THREAD, &App::OnTerminate, this, MSG_TERMINATE);
    Bind(wxEVT_COMMAND_THREAD, &App::OnShowCheckingUpdates, this, MSG_SHOW_CHECKING_UPDATES);
    Bind(wxEVT_COMMAND_THREAD, &App::OnNoUpdateFound, this, MSG_NO_UPDATE_FOUND);
}

void App::SendMsg(int msg)
{
    wxThreadEvent *event = new wxThreadEvent(wxEVT_COMMAND_THREAD, msg);
    wxQueueEvent(this, event);
}

void App::ShowWindow()
{
    if ( m_win )
    {
        m_win->Raise();
        return;
    }

    m_win = new UpdateDialog();
    m_win->Bind(wxEVT_CLOSE_WINDOW, &App::OnWindowClose, this);
    m_win->Show();
}

void App::OnWindowClose(wxCloseEvent& event)
{
    m_win = NULL;
    event.Skip();
}

void App::OnTerminate(wxThreadEvent&)
{
    ExitMainLoop();
}

void App::OnShowCheckingUpdates(wxThreadEvent&)
{
    ShowWindow();
    m_win->StateCheckingUpdates();
}

void App::OnNoUpdateFound(wxThreadEvent&)
{
    if ( m_win )
        m_win->StateNoUpdateFound();
}

/*--------------------------------------------------------------------------*
                             winsparkle::UI class
 *--------------------------------------------------------------------------*/

// helper for accessing the UI thread
class UIThreadAccess
{
public:
    UIThreadAccess() : m_lock(ms_uiThreadCS) {}

    App& App()
    {
        StartIfNeeded();
        return wxGetApp();
    };

    bool IsRunning() const { return ms_uiThread != NULL; }

    // intentionally not static, to force locking before access
    UI* UIThread() { return ms_uiThread; }

    void ShutDownThread()
    {
        if ( ms_uiThread )
        {
            ms_uiThread->Join();
            ms_uiThread = NULL;
        }
    }

private:
    void StartIfNeeded()
    {
        // if the thread is not running yet, we have to start it
        if ( !ms_uiThread )
        {
            ms_uiThread = new UI();
            ms_uiThread->Start();
        }
    }

    CriticalSectionLocker m_lock;

    static UI *ms_uiThread;
    static CriticalSection ms_uiThreadCS;
};

UI *UIThreadAccess::ms_uiThread = NULL;
CriticalSection UIThreadAccess::ms_uiThreadCS;

HINSTANCE UI::ms_hInstance = NULL;

UI::UI() : Thread("WinSparkle UI thread")
{
}

void UI::Run()
{
    // Note: The thread that called UI::Get() holds gs_uiThreadCS
    //       at this point and won't release it until we signal it.

    // We need to pass correct HINSTANCE to wxEntry() and the right value is
    // HINSTANCE of this DLL, not of the main .exe.

    if ( !ms_hInstance )
        return; // DllMain() not called? -- FIXME: throw

    // IMPLEMENT_WXWIN_MAIN does this as the first thing
    wxDISABLE_DEBUG_SUPPORT();

    // We do this before wxEntry() explicitly, even though wxEntry() would
    // do it too, so that we know when wx is initialized and can signal
    // run_wx_gui_from_dll() about it *before* starting the event loop.
    wxInitializer wxinit;
    if ( !wxinit.IsOk() )
        return; // failed to init wx -- FIXME: throw

    // Signal run_wx_gui_from_dll() that it can continue
    SignalReady();

    // Run the app:
    wxEntry(ms_hInstance);
}

/*static*/
void UI::ShutDown()
{
    UIThreadAccess uit;

    if ( !uit.IsRunning() )
        return;

    uit.App().SendMsg(MSG_TERMINATE);
    uit.ShutDownThread();
}

/*static*/
void UI::NotifyNoUpdates()
{
    UIThreadAccess uit;

    if ( !uit.IsRunning() )
        return;

    uit.App().SendMsg(MSG_NO_UPDATE_FOUND);
}

/*static*/
void UI::ShowCheckingUpdates()
{
    UIThreadAccess uit;
    uit.App().SendMsg(MSG_SHOW_CHECKING_UPDATES);
}

} // namespace winsparkle
<commit_msg>Use Sparkle-s "%s is currently the newest version available." string.<commit_after>/*
 *  This file is part of WinSparkle (http://winsparkle.org)
 *
 *  Copyright (C) 2009 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

// silence warnings in wxWidgets' CRT wrappers
#define _CRT_SECURE_NO_WARNINGS

#include "ui.h"
#include "settings.h"

#define wxNO_NET_LIB
#define wxNO_XML_LIB
#define wxNO_XRC_LIB
#define wxNO_ADV_LIB
#define wxNO_HTML_LIB
#include <wx/setup.h>

#include <wx/app.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/gauge.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
#include <wx/timer.h>

#if !wxCHECK_VERSION(2,9,0)
#error "wxWidgets >= 2.9 is required to compile this code"
#endif

namespace winsparkle
{

/*--------------------------------------------------------------------------*
                       Window for communicating with the user
 *--------------------------------------------------------------------------*/

class UpdateDialog : public wxDialog
{
public:
    UpdateDialog();

    // changes state into "checking for updates"
    void StateCheckingUpdates();
    // change state into "no updates found"
    void StateNoUpdateFound();

private:
    void EnablePulsing(bool enable);
    void OnTimer(wxTimerEvent& event);
    void OnCloseButton(wxCommandEvent& event);
    void OnClose(wxCloseEvent& event);

private:
    wxTimer       m_timer;
    wxSizer      *m_infoSizer;
    wxSizer      *m_buttonSizer;
    wxStaticText *m_message;
    wxGauge      *m_progress;
    wxButton     *m_closeButton;
};

UpdateDialog::UpdateDialog()
    : wxDialog(NULL, wxID_ANY, _("Software Update"),
               wxDefaultPosition, wxDefaultSize,
               wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
      m_timer(this)
{
    SetIcons(wxICON(UpdateAvailable));

    wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);

    wxSizer *topSizer = new wxBoxSizer(wxHORIZONTAL);
    wxIcon bigIcon("UpdateAvailable", wxBITMAP_TYPE_ICO_RESOURCE, 48, 48);
    topSizer->Add
              (
                  new wxStaticBitmap(this, wxID_ANY, bigIcon),
                  wxSizerFlags(0).Border(wxALL, 10)
              );

    m_infoSizer = new wxBoxSizer(wxVERTICAL);
    topSizer->Add(m_infoSizer, wxSizerFlags(1).Expand().Border(wxALL, 10));

    m_message = new wxStaticText(this, wxID_ANY, "");
    m_infoSizer->Add(m_message, wxSizerFlags(0).Expand().Border(wxBOTTOM, 10));

    m_progress = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(300, 16));
    m_infoSizer->Add(m_progress, wxSizerFlags(0).Expand());

    m_buttonSizer = new wxBoxSizer(wxHORIZONTAL);
    m_closeButton = new wxButton(this, wxID_CANCEL);
    m_buttonSizer->Add(m_closeButton, wxSizerFlags(0).Border(wxLEFT));

    mainSizer->Add(topSizer, wxSizerFlags(1).Expand());
    mainSizer->Add
               (
                   m_buttonSizer,
                   wxSizerFlags(0).Right().Border(wxLEFT|wxRIGHT|wxBOTTOM, 10)
               );

    SetSizerAndFit(mainSizer);

    Bind(wxEVT_CLOSE_WINDOW, &UpdateDialog::OnClose, this);
    Bind(wxEVT_TIMER, &UpdateDialog::OnTimer, this);
    Bind(wxEVT_COMMAND_BUTTON_CLICKED, &UpdateDialog::OnCloseButton, this, wxID_CANCEL);
}

void UpdateDialog::EnablePulsing(bool enable)
{
    if ( enable && !m_timer.IsRunning() )
        m_timer.Start(100);
    else if ( !enable && m_timer.IsRunning() )
        m_timer.Stop();
}

void UpdateDialog::OnTimer(wxTimerEvent&)
{
    m_progress->Pulse();
}

void UpdateDialog::OnCloseButton(wxCommandEvent&)
{
    Close();
}

void UpdateDialog::OnClose(wxCloseEvent&)
{
    // We need to override this, because by default, wxDialog doesn't
    // destroy itself in Close().
    Destroy();
}

#define SHOW(c)    (c)->GetContainingSizer()->Show(c)
#define HIDE(c)    (c)->GetContainingSizer()->Hide(c)

void UpdateDialog::StateCheckingUpdates()
{
    m_message->SetLabel(_("Checking for updates..."));

    SHOW(m_progress);
    SHOW(m_closeButton);
    m_closeButton->SetLabel(_("Cancel"));
    EnablePulsing(true);
}

void UpdateDialog::StateNoUpdateFound()
{
    wxString msg;
    try
    {
        msg = wxString::Format
              (
                  _("%s is currently the newest version available."),
                  Settings::Get().GetAppVersion()
              );
    }
    catch ( std::exception& )
    {
        // GetAppVersion() may fail
        msg = "Error: Updates checking not properly configured.";
    }

    m_message->SetLabel(msg);

    HIDE(m_progress);
    m_closeButton->SetLabel(_("Close"));
    EnablePulsing(false);
}

/*--------------------------------------------------------------------------*
                             Inter-thread messages
 *--------------------------------------------------------------------------*/

// Terminate the wx thread
const int MSG_TERMINATE = wxNewId();

// Show "Checking for updates..." window
const int MSG_SHOW_CHECKING_UPDATES = wxNewId();

// Notify the UI that there were no updates
const int MSG_NO_UPDATE_FOUND = wxNewId();

/*--------------------------------------------------------------------------*
                                Application
 *--------------------------------------------------------------------------*/

class App : public wxApp
{
public:
    App();

    // Sends a message with ID @a msg to the app.
    void SendMsg(int msg);

private:
    void ShowWindow();

    void OnWindowClose(wxCloseEvent& event);
    void OnTerminate(wxThreadEvent& event);
    void OnShowCheckingUpdates(wxThreadEvent& event);
    void OnNoUpdateFound(wxThreadEvent& event);

private:
    UpdateDialog *m_win;
};

IMPLEMENT_APP_NO_MAIN(App)

App::App()
{
    m_win = NULL;

    // Keep the wx "main" thread running even without windows. This greatly
    // simplifies threads handling, because we don't have to correctly
    // implement wx-thread restarting.
    //
    // Note that this only works if we don't explicitly call ExitMainLoop(),
    // except in reaction to win_sparkle_cleanup()'s message.
    // win_sparkle_cleanup() relies on the availability of wxApp instance and
    // if the event loop terminated, wxEntry() would return and wxApp instance
    // would be destroyed.
    //
    // Also note that this is efficient, because if there are no windows, the
    // thread will sleep waiting for a new event. We could safe some memory
    // by shutting the thread down when it's no longer needed, though.
    SetExitOnFrameDelete(false);

    // Bind events to their handlers:
    Bind(wxEVT_COMMAND_THREAD, &App::OnTerminate, this, MSG_TERMINATE);
    Bind(wxEVT_COMMAND_THREAD, &App::OnShowCheckingUpdates, this, MSG_SHOW_CHECKING_UPDATES);
    Bind(wxEVT_COMMAND_THREAD, &App::OnNoUpdateFound, this, MSG_NO_UPDATE_FOUND);
}

void App::SendMsg(int msg)
{
    wxThreadEvent *event = new wxThreadEvent(wxEVT_COMMAND_THREAD, msg);
    wxQueueEvent(this, event);
}

void App::ShowWindow()
{
    if ( m_win )
    {
        m_win->Raise();
        return;
    }

    m_win = new UpdateDialog();
    m_win->Bind(wxEVT_CLOSE_WINDOW, &App::OnWindowClose, this);
    m_win->Show();
}

void App::OnWindowClose(wxCloseEvent& event)
{
    m_win = NULL;
    event.Skip();
}

void App::OnTerminate(wxThreadEvent&)
{
    ExitMainLoop();
}

void App::OnShowCheckingUpdates(wxThreadEvent&)
{
    ShowWindow();
    m_win->StateCheckingUpdates();
}

void App::OnNoUpdateFound(wxThreadEvent&)
{
    if ( m_win )
        m_win->StateNoUpdateFound();
}

/*--------------------------------------------------------------------------*
                             winsparkle::UI class
 *--------------------------------------------------------------------------*/

// helper for accessing the UI thread
class UIThreadAccess
{
public:
    UIThreadAccess() : m_lock(ms_uiThreadCS) {}

    App& App()
    {
        StartIfNeeded();
        return wxGetApp();
    };

    bool IsRunning() const { return ms_uiThread != NULL; }

    // intentionally not static, to force locking before access
    UI* UIThread() { return ms_uiThread; }

    void ShutDownThread()
    {
        if ( ms_uiThread )
        {
            ms_uiThread->Join();
            ms_uiThread = NULL;
        }
    }

private:
    void StartIfNeeded()
    {
        // if the thread is not running yet, we have to start it
        if ( !ms_uiThread )
        {
            ms_uiThread = new UI();
            ms_uiThread->Start();
        }
    }

    CriticalSectionLocker m_lock;

    static UI *ms_uiThread;
    static CriticalSection ms_uiThreadCS;
};

UI *UIThreadAccess::ms_uiThread = NULL;
CriticalSection UIThreadAccess::ms_uiThreadCS;

HINSTANCE UI::ms_hInstance = NULL;

UI::UI() : Thread("WinSparkle UI thread")
{
}

void UI::Run()
{
    // Note: The thread that called UI::Get() holds gs_uiThreadCS
    //       at this point and won't release it until we signal it.

    // We need to pass correct HINSTANCE to wxEntry() and the right value is
    // HINSTANCE of this DLL, not of the main .exe.

    if ( !ms_hInstance )
        return; // DllMain() not called? -- FIXME: throw

    // IMPLEMENT_WXWIN_MAIN does this as the first thing
    wxDISABLE_DEBUG_SUPPORT();

    // We do this before wxEntry() explicitly, even though wxEntry() would
    // do it too, so that we know when wx is initialized and can signal
    // run_wx_gui_from_dll() about it *before* starting the event loop.
    wxInitializer wxinit;
    if ( !wxinit.IsOk() )
        return; // failed to init wx -- FIXME: throw

    // Signal run_wx_gui_from_dll() that it can continue
    SignalReady();

    // Run the app:
    wxEntry(ms_hInstance);
}

/*static*/
void UI::ShutDown()
{
    UIThreadAccess uit;

    if ( !uit.IsRunning() )
        return;

    uit.App().SendMsg(MSG_TERMINATE);
    uit.ShutDownThread();
}

/*static*/
void UI::NotifyNoUpdates()
{
    UIThreadAccess uit;

    if ( !uit.IsRunning() )
        return;

    uit.App().SendMsg(MSG_NO_UPDATE_FOUND);
}

/*static*/
void UI::ShowCheckingUpdates()
{
    UIThreadAccess uit;
    uit.App().SendMsg(MSG_SHOW_CHECKING_UPDATES);
}

} // namespace winsparkle
<|endoftext|>


<commit_before>
#include "Cache.hpp"

#include "GlobalAllocator.hpp"
#include "Delegate.hpp"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE( Cache_tests );

int64_t foo = 1234;
int64_t bar[4] = { 2345, 3456, 4567, 6789 };

void user_main( thread * me, void * args )
{
  {
    Incoherent< int64_t >::RO buf( GlobalAddress< int64_t >::TwoDimensional( &foo ), 1 );
    BOOST_CHECK_EQUAL( *buf, foo );
  }

  {
    {
      Incoherent<int64_t>::RW buf( GlobalAddress< int64_t >::TwoDimensional( &foo ), 1 );
      BOOST_CHECK_EQUAL( *buf, foo );
      foo = 1235;
      BOOST_CHECK( *buf != foo );
      BOOST_CHECK_EQUAL( foo, 1235 );
      *buf = 1235;
      BOOST_CHECK_EQUAL( *buf, foo );
      *buf = 1236;
    }
    BOOST_CHECK_EQUAL( foo, 1236 );
  }

  {
    int64_t x;
    Incoherent<int64_t>::RO buf( GlobalAddress< int64_t >::TwoDimensional( &foo ), 1, &x );
    BOOST_CHECK_EQUAL( *buf, foo );
  }

  {
    int64_t y[4];
    Incoherent<int64_t>::RO buf2( GlobalAddress< int64_t >::TwoDimensional( bar ), 4, &y[0] );
    BOOST_CHECK_EQUAL( buf2[2], bar[2] );
  }

  {
    Incoherent<int64_t>::RW buf3( GlobalAddress< int64_t >::TwoDimensional( bar ), 4);
    BOOST_CHECK_EQUAL( buf3[2], bar[2] );
  }

  {
    // test for early wakeup handled properly
    BOOST_MESSAGE( "Wakeup test" );
    Incoherent<int64_t>::RW buf4( GlobalAddress< int64_t >::TwoDimensional( bar, 1 ), 1);
    buf4.start_acquire( );
    for (int i=0; i<2000; i++) {
        SoftXMT_yield(); // spin to let reply come back
    }
    buf4.block_until_acquired( );

    buf4.start_release( );
    for (int i=0; i<2000; i++) {
        SoftXMT_yield(); // spin to let reply come back
    }
    buf4.block_until_released( );
  }

  {
    const size_t array_size = 128;
    LOG(INFO) << "Mallocing " << array_size << " words";
    GlobalAddress< int64_t > array = SoftXMT_typed_malloc< int64_t >( array_size );

    // write indices properly
    LOG(INFO) << "writing indices";
    for( int i = 0; i < array_size; ++i ) {
      SoftXMT_delegate_write_word( array + i, i );
    }

    // check that we can read a word at a time
    LOG(INFO) << "verifying word reads";
    for( int i = 0; i < array_size; ++i ) {
      LOG(INFO) << "checking element " << i;
      Incoherent<int64_t>::RO d( array + i, 1 );
      BOOST_CHECK_EQUAL( i, *d );
      int64_t dd = SoftXMT_delegate_read_word( array + i );
      BOOST_CHECK_EQUAL( i, dd );
      BOOST_CHECK_EQUAL( dd, *d );
    }

    // check that we can read two words at a time
    // LOG(INFO) << "verifying block reads";
    // for( int i = 0; i < array_size; ++i ) {
    //   Incoherent<int64_t>::RO d( array + i, 2 );
    //   BOOST_CHECK_EQUAL( i, d[0] );
    //   if( i+1 < array_size ) BOOST_CHECK_EQUAL( i+1, d[1] );
    // }

    LOG(INFO) << "verifying block reads";
    for( int size = 1; size < array_size; ++size ) {
      LOG(INFO) << "checking blocks of size " << size;
      for( int start = 0; start < array_size; ++start ) {
        //LOG(INFO) << "checking from start " << start;
        int actual_size = ( start + size > array_size ? array_size : start + size ) - start;
        DVLOG(5) << "starting iteration with start:" << start
                 << " size:" << size
                 << " actual_size:" << actual_size;

        DVLOG(5) << "*****************************************************************************";
        //start:2 size:4 actual_size:4 i:2
        if( start == 2 && size == 4 ) {
          BOOST_CHECK_EQUAL( 2, SoftXMT_delegate_read_word( array + start + 0 ) );
          BOOST_CHECK_EQUAL( 3, SoftXMT_delegate_read_word( array + start + 1 ) );
          BOOST_CHECK_EQUAL( 4, SoftXMT_delegate_read_word( array + start + 2 ) );
          BOOST_CHECK_EQUAL( 5, SoftXMT_delegate_read_word( array + start + 3 ) );
        }
        DVLOG(5) << "*****************************************************************************";

        {
          Incoherent<int64_t>::RW d( array + start, actual_size );
          d.block_until_acquired();
          DVLOG(5) << "*****************************************************************************";
          for( int i = start; i < actual_size; ++i ) {
            DVLOG(5) << "checking word with start:" << start
                     << " size:" << size
                     << " actual_size:" << actual_size
                     << " i:" << i;
            BOOST_CHECK_EQUAL( i, d[i - start] );
            CHECK_EQ( i, d[i - start] ) << "start:" << start
                                        << " size:" << size
                                        << " actual_size:" << actual_size
                                        << " i:" << i;
	    d[i - start] = i;
          }
        }
      }
    }

    // check that we can read the words that were written
    LOG(INFO) << "verifying word writes";
    for( int i = 0; i < array_size; ++i ) {
      LOG(INFO) << "checking element " << i;
      //Incoherent<int64_t>::RO d( array + i, 1 );
      //BOOST_CHECK_EQUAL( i, *d );
      int64_t dd = SoftXMT_delegate_read_word( array + i );
      BOOST_CHECK_EQUAL( i, dd );
      //BOOST_CHECK_EQUAL( dd, *d );
    }

    SoftXMT_free( array );
  }

  SoftXMT_signal_done();
}

BOOST_AUTO_TEST_CASE( test1 ) {

  SoftXMT_init( &(boost::unit_test::framework::master_test_suite().argc),
                &(boost::unit_test::framework::master_test_suite().argv),
                1 << 23);

  SoftXMT_activate();

  BOOST_CHECK_EQUAL( SoftXMT_nodes(), 2 );
  SoftXMT_run_user_main( &user_main, NULL );
  BOOST_CHECK( SoftXMT_done() == true );

  SoftXMT_finish( 0 );
}

BOOST_AUTO_TEST_SUITE_END();

<commit_msg>pass Allocator,Aggregator,Cache tests<commit_after>
#include "Cache.hpp"

#include "GlobalAllocator.hpp"
#include "Delegate.hpp"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE( Cache_tests );

int64_t foo = 1234;
int64_t bar[4] = { 2345, 3456, 4567, 6789 };

void user_main( Thread * me, void * args )
{
  {
    Incoherent< int64_t >::RO buf( GlobalAddress< int64_t >::TwoDimensional( &foo ), 1 );
    BOOST_CHECK_EQUAL( *buf, foo );
  }

  {
    {
      Incoherent<int64_t>::RW buf( GlobalAddress< int64_t >::TwoDimensional( &foo ), 1 );
      BOOST_CHECK_EQUAL( *buf, foo );
      foo = 1235;
      BOOST_CHECK( *buf != foo );
      BOOST_CHECK_EQUAL( foo, 1235 );
      *buf = 1235;
      BOOST_CHECK_EQUAL( *buf, foo );
      *buf = 1236;
    }
    BOOST_CHECK_EQUAL( foo, 1236 );
  }

  {
    int64_t x;
    Incoherent<int64_t>::RO buf( GlobalAddress< int64_t >::TwoDimensional( &foo ), 1, &x );
    BOOST_CHECK_EQUAL( *buf, foo );
  }

  {
    int64_t y[4];
    Incoherent<int64_t>::RO buf2( GlobalAddress< int64_t >::TwoDimensional( bar ), 4, &y[0] );
    BOOST_CHECK_EQUAL( buf2[2], bar[2] );
  }

  {
    Incoherent<int64_t>::RW buf3( GlobalAddress< int64_t >::TwoDimensional( bar ), 4);
    BOOST_CHECK_EQUAL( buf3[2], bar[2] );
  }

  {
    // test for early wakeup handled properly
    BOOST_MESSAGE( "Wakeup test" );
    Incoherent<int64_t>::RW buf4( GlobalAddress< int64_t >::TwoDimensional( bar, 1 ), 1);
    buf4.start_acquire( );
    for (int i=0; i<2000; i++) {
        SoftXMT_yield(); // spin to let reply come back
    }
    buf4.block_until_acquired( );

    buf4.start_release( );
    for (int i=0; i<2000; i++) {
        SoftXMT_yield(); // spin to let reply come back
    }
    buf4.block_until_released( );
  }

  {
    const size_t array_size = 128;
    LOG(INFO) << "Mallocing " << array_size << " words";
    GlobalAddress< int64_t > array = SoftXMT_typed_malloc< int64_t >( array_size );

    // write indices properly
    LOG(INFO) << "writing indices";
    for( int i = 0; i < array_size; ++i ) {
      SoftXMT_delegate_write_word( array + i, i );
    }

    // check that we can read a word at a time
    LOG(INFO) << "verifying word reads";
    for( int i = 0; i < array_size; ++i ) {
      LOG(INFO) << "checking element " << i;
      Incoherent<int64_t>::RO d( array + i, 1 );
      BOOST_CHECK_EQUAL( i, *d );
      int64_t dd = SoftXMT_delegate_read_word( array + i );
      BOOST_CHECK_EQUAL( i, dd );
      BOOST_CHECK_EQUAL( dd, *d );
    }

    // check that we can read two words at a time
    // LOG(INFO) << "verifying block reads";
    // for( int i = 0; i < array_size; ++i ) {
    //   Incoherent<int64_t>::RO d( array + i, 2 );
    //   BOOST_CHECK_EQUAL( i, d[0] );
    //   if( i+1 < array_size ) BOOST_CHECK_EQUAL( i+1, d[1] );
    // }

    LOG(INFO) << "verifying block reads";
    for( int size = 1; size < array_size; ++size ) {
      LOG(INFO) << "checking blocks of size " << size;
      for( int start = 0; start < array_size; ++start ) {
        //LOG(INFO) << "checking from start " << start;
        int actual_size = ( start + size > array_size ? array_size : start + size ) - start;
        DVLOG(5) << "starting iteration with start:" << start
                 << " size:" << size
                 << " actual_size:" << actual_size;

        DVLOG(5) << "*****************************************************************************";
        //start:2 size:4 actual_size:4 i:2
        if( start == 2 && size == 4 ) {
          BOOST_CHECK_EQUAL( 2, SoftXMT_delegate_read_word( array + start + 0 ) );
          BOOST_CHECK_EQUAL( 3, SoftXMT_delegate_read_word( array + start + 1 ) );
          BOOST_CHECK_EQUAL( 4, SoftXMT_delegate_read_word( array + start + 2 ) );
          BOOST_CHECK_EQUAL( 5, SoftXMT_delegate_read_word( array + start + 3 ) );
        }
        DVLOG(5) << "*****************************************************************************";

        {
          Incoherent<int64_t>::RW d( array + start, actual_size );
          d.block_until_acquired();
          DVLOG(5) << "*****************************************************************************";
          for( int i = start; i < actual_size; ++i ) {
            DVLOG(5) << "checking word with start:" << start
                     << " size:" << size
                     << " actual_size:" << actual_size
                     << " i:" << i;
            BOOST_CHECK_EQUAL( i, d[i - start] );
            CHECK_EQ( i, d[i - start] ) << "start:" << start
                                        << " size:" << size
                                        << " actual_size:" << actual_size
                                        << " i:" << i;
	    d[i - start] = i;
          }
        }
      }
    }

    // check that we can read the words that were written
    LOG(INFO) << "verifying word writes";
    for( int i = 0; i < array_size; ++i ) {
      LOG(INFO) << "checking element " << i;
      //Incoherent<int64_t>::RO d( array + i, 1 );
      //BOOST_CHECK_EQUAL( i, *d );
      int64_t dd = SoftXMT_delegate_read_word( array + i );
      BOOST_CHECK_EQUAL( i, dd );
      //BOOST_CHECK_EQUAL( dd, *d );
    }

    SoftXMT_free( array );
  }

  SoftXMT_signal_done();
}

BOOST_AUTO_TEST_CASE( test1 ) {

  SoftXMT_init( &(boost::unit_test::framework::master_test_suite().argc),
                &(boost::unit_test::framework::master_test_suite().argv),
                1 << 23);

  SoftXMT_activate();

  BOOST_CHECK_EQUAL( SoftXMT_nodes(), 2 );
  SoftXMT_run_user_main( &user_main, NULL );
  BOOST_CHECK( SoftXMT_done() == true );

  SoftXMT_finish( 0 );
}

BOOST_AUTO_TEST_SUITE_END();

<|endoftext|>


<commit_before>#include "CMO_score.h"
#include "GameManager.h"

USING_NS_CC;

bool CMO_score::init()
{
	if ( !CCSprite::init() )
    {
        return false;
    }

	pScore = NULL;
    m_isTaken = false;
    return true;
}

void CMO_score::setImage(IndexedPosition indexedPosition)
{
	m_Index = indexedPosition;
}

void CMO_score::update( float delta )
{
    MO_ITEM tempItem = CGameManager::GetInstance()->GetItem(m_Index);
    MO_OWNER tempOwner = CGameManager::GetInstance()->GetMapOwner(m_Index);
    if(tempOwner != MO_NOBODY && m_isTaken==false)
    {
        // 애니메이션이 시작하는 시간은 라인이 재생되는 시간 + 인덱스가 낮은 타일들이 모두 그려지는 시간(애니메이션이 있는 타일은 인덱스 1부터 시작하므로 자신의 인덱스에서 1을 빼서 재생시간 곱함)
        float delayTime = PLAYSCENE_ANIMATION_TIME + PLAYSCENE_ANIMATION_TIME * (CGameManager::GetInstance()->GetTileAnimationTurn(m_Index) - 1);

        // 애니메이션이 끝나는 시간을 지정함
		CGameManager::GetInstance()->SetAnimationDelay(delayTime);

		CCDelayTime *dt = CCDelayTime::create(delayTime);
        m_isTaken = true;

        switch (tempItem) {
            case ITEM_NOTHING:
                pScore = CCSprite::create(PLAYSCENE_SCORE_LAND.c_str());
                break;
            case ITEM_GOLD:
                pScore = CCSprite::create(PLAYSCENE_SCORE_CAKE.c_str());
                break;
            case ITEM_TRASH:
                pScore = CCSprite::create(PLAYSCENE_SCORE_TRASH.c_str());
                break;
            default:
                break;
        }

        CCFadeOut* FadeOut = CCFadeOut::create(0.8f);
        CCMoveBy* actionBy = CCMoveBy::create(0.8f, ccp(0.0f,80.0f));
        CCAction* simul = CCSpawn::create(dt,FadeOut,actionBy);
        //CCAction *Fadeactions = CCSequence::create(dt, FadeOut, NULL);
        pScore->setOpacity(0);
        pScore->setAnchorPoint( ccp(0, 0.5f) );
        pScore->runAction(simul);
        addChild(pScore,1);
    }

}<commit_msg>점수 원하는 모양으로 나오게 바꿈!!!  CCSpawn쓰지말고 그냥 runAction두<commit_after>#include "CMO_score.h"
#include "GameManager.h"

USING_NS_CC;

bool CMO_score::init()
{
	if ( !CCSprite::init() )
    {
        return false;
    }

	pScore = NULL;
    m_isTaken = false;
    return true;
}

void CMO_score::setImage(IndexedPosition indexedPosition)
{
	m_Index = indexedPosition;
}

void CMO_score::update( float delta )
{
    MO_ITEM tempItem = CGameManager::GetInstance()->GetItem(m_Index);
    MO_OWNER tempOwner = CGameManager::GetInstance()->GetMapOwner(m_Index);
    if(tempOwner != MO_NOBODY && m_isTaken==false)
    {
        // 애니메이션이 시작하는 시간은 라인이 재생되는 시간 + 인덱스가 낮은 타일들이 모두 그려지는 시간(애니메이션이 있는 타일은 인덱스 1부터 시작하므로 자신의 인덱스에서 1을 빼서 재생시간 곱함)
        float delayTime = PLAYSCENE_ANIMATION_TIME + PLAYSCENE_ANIMATION_TIME * (CGameManager::GetInstance()->GetTileAnimationTurn(m_Index) - 1);

        // 애니메이션이 끝나는 시간을 지정함
		CGameManager::GetInstance()->SetAnimationDelay(delayTime);

		CCDelayTime *dt = CCDelayTime::create(delayTime);
        m_isTaken = true;

        switch (tempItem) {
            case ITEM_NOTHING:
                pScore = CCSprite::create(PLAYSCENE_SCORE_LAND.c_str());
                break;
            case ITEM_GOLD:
                pScore = CCSprite::create(PLAYSCENE_SCORE_CAKE.c_str());
                break;
            case ITEM_TRASH:
                pScore = CCSprite::create(PLAYSCENE_SCORE_TRASH.c_str());
                break;
            default:
                break;
        }

        //점수 애니메이션 부분

        CCFadeOut* FadeOut = CCFadeOut::create(0.8f);
        CCMoveBy* actionBy = CCMoveBy::create(0.8f, ccp(0.0f,80.0f));
        CCAction* simul = CCSequence::create(dt,FadeOut,NULL);
        //CCAction *Fadeactions = CCSequence::create(dt, FadeOut, NULL);
        pScore->setOpacity(0);
        pScore->setAnchorPoint( ccp(0, 0.5f) );
        pScore->runAction(simul);

        CCAction* simul1 = CCSequence::create(dt,actionBy,NULL);
        pScore->runAction(simul1);

        addChild(pScore,1);
    }

}<|endoftext|>


<commit_before>#include <assert.h>
#include <iostream>
#include <memory>
#include <vector>

#include "common/simhubdeviceplugin.h"
#include "main.h"

// -- public C FFI

extern "C" {
int simplug_init(SPHANDLE *plugin_instance, LoggingFunctionCB logger)
{
    *plugin_instance = new SimSourcePluginStateManager(logger);
    return 0;
}

int simplug_config_passthrough(SPHANDLE plugin_instance, void *libconfig_instance)
{
    return static_cast<PluginStateManager *>(plugin_instance)->configPassthrough(static_cast<libconfig::Config *>(libconfig_instance));
}

int simplug_preflight_complete(SPHANDLE plugin_instance)
{
    return static_cast<PluginStateManager *>(plugin_instance)->preflightComplete();
}

void simplug_commence_eventing(SPHANDLE plugin_instance, EnqueueEventHandler enqueue_callback, void *arg)
{
    static_cast<PluginStateManager *>(plugin_instance)->commenceEventing(enqueue_callback, arg);
}

int simplug_deliver_value(SPHANDLE plugin_instance, GenericTLV *value)
{
    return static_cast<PluginStateManager *>(plugin_instance)->deliverValue(value);
}

void simplug_cease_eventing(SPHANDLE plugin_instance)
{
    static_cast<PluginStateManager *>(plugin_instance)->ceaseEventing();
}

void simplug_release(SPHANDLE plugin_instance)
{
    assert(plugin_instance);
    delete static_cast<PluginStateManager *>(plugin_instance);
}
}

// -- internal implementation

SimSourcePluginStateManager *SimSourcePluginStateManager::_StateManagerInstance = NULL;

void SimSourcePluginStateManager::AllocBuffer(uv_handle_t *handle, size_t size, uv_buf_t *buf)
{
    *buf = SimSourcePluginStateManager::StateManagerInstance()->_readBuffer;
}

//! static getter for singleton instance of our class
SimSourcePluginStateManager *SimSourcePluginStateManager::StateManagerInstance(void)
{
    return _StateManagerInstance;
}

SimSourcePluginStateManager::SimSourcePluginStateManager(LoggingFunctionCB logger)
    : PluginStateManager(logger)
{
    // enforce singleton pre-condition

    assert(!_StateManagerInstance);

    _StateManagerInstance = this;
    _processedElementCount = 0;

    if (!(_rawBuffer = (char *)malloc(BUFFER_LEN))) {
        printf("Unable to allocate buffer of size %d", BUFFER_LEN);
    }
    else {
        _readBuffer = ::uv_buf_init(_rawBuffer, BUFFER_LEN);
    }
}

SimSourcePluginStateManager::~SimSourcePluginStateManager(void)
{
    // TODO: enable once shtudown implemented
    if (_pluginThread != NULL) {
        if (_pluginThread->joinable()) {
            ceaseEventing();
            _pluginThread->join();
        }

        delete _pluginThread;
    }

    if (_rawBuffer != NULL)
        free(_rawBuffer);
}

int SimSourcePluginStateManager::preflightComplete(void)
{
    int retVal = PREFLIGHT_OK;
    int port = 8091;

    libconfig::Setting *devicesConfiguraiton = NULL;

    std::string type = "";
    std::string ipAddress = "";

    try {
        devicesConfiguraiton = &_config->lookup("configuration");
    }
    catch (const libconfig::SettingNotFoundException &nfex) {
        _logger(LOG_ERROR, "Config file parse error at %s. Skipping....", nfex.getPath());
    }

    for (libconfig::SettingIterator iter = devicesConfiguraiton->begin(); iter != devicesConfiguraiton->end(); iter++) {

        if (iter->exists("ipAddress")) {
            iter->lookupValue("ipAddress", ipAddress);
        }
        else {
            ipAddress = "127.0.0.1";
        }

        if (iter->exists("port")) {
            iter->lookupValue("port", port);
        }
    }

    struct sockaddr_in req_addr;

    _eventLoop = uv_default_loop();
    check_uv(uv_loop_init(_eventLoop));

    check_uv(uv_tcp_init(_eventLoop, &_tcpClient));
    uv_tcp_keepalive(&_tcpClient, 1, 60);

    uv_ip4_addr(ipAddress.c_str(), port, &req_addr);

    int connectErr = uv_tcp_connect(&_connectReq, &_tcpClient, (struct sockaddr *)&req_addr, &SimSourcePluginStateManager::OnConnect);

    if (connectErr < 0) {
        retVal = PREFLIGHT_FAIL;
    }

    return retVal;
}

void SimSourcePluginStateManager::OnConnect(uv_connect_t *req, int status)
{
    assert(SimSourcePluginStateManager::StateManagerInstance());

    if (status == SIM_CONNECT_NOT_FOUND) {
        SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_ERROR, "   - Failed to connect to simulator");
    }
    else {
        SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_INFO, " - Connected to simulator %d", status);
        SimSourcePluginStateManager::StateManagerInstance()->instanceConnectionHandler(req, status);
    }
}

void SimSourcePluginStateManager::OnRead(uv_stream_t *server, ssize_t nread, const uv_buf_t *buf)
{
    SimSourcePluginStateManager::StateManagerInstance()->instanceReadHandler(server, nread, buf);
}

void SimSourcePluginStateManager::OnClose(uv_handle_t *handle)
{
    assert(SimSourcePluginStateManager::StateManagerInstance());
    SimSourcePluginStateManager::StateManagerInstance()->instanceCloseHandler(handle);
}

void SimSourcePluginStateManager::instanceConnectionHandler(uv_connect_t *req, int status)
{
    if (uv_is_readable(req->handle)) {
        uv_read_start(req->handle, &SimSourcePluginStateManager::AllocBuffer, &SimSourcePluginStateManager::OnRead);
    }
    else {
        printf("not readable\n");
    }
}

void SimSourcePluginStateManager::instanceReadHandler(uv_stream_t *server, ssize_t nread, const uv_buf_t *buf)
{
    if (nread > 0) {
        uv_buf_t buffer = uv_buf_init((char *)malloc(nread), nread);
        memcpy(buffer.base, buf->base, nread);
        buffer.base[nread - 1] = '\0';
        processData(buffer.base, nread);
        free(buffer.base);
    }
    else if (nread < 0) {
        if (nread == UV_EOF) {
            SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_INFO, " - Stopping prepare3d ingest loop");
            ceaseEventing();
        }
        else {
            SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_INFO, " - %s", uv_strerror(nread));
            uv_close((uv_handle_t *)server, &SimSourcePluginStateManager::OnClose);
        }
    }
}

void SimSourcePluginStateManager::processData(char *data, int len)
{
    if (len > 2) {
        int elementCount = 0;
        char *p = strtok(data, "\n");
        char *array[MAX_ELEMENTS_PER_UPDATE];

        while (p != NULL) {
            size_t len = strlen(p);

            if (len > 2) {
                char *buffer = (char *)malloc(BUFFER_LEN);
                memset(buffer, 0, BUFFER_LEN);
                strncpy(buffer, p, len);
                buffer[len - 1] = '\0';
                array[elementCount++] = buffer;
            }

            p = strtok(NULL, "\n");
        }

        for (int i = 0; i < elementCount; ++i) {
            processElement(array[i]);
            free(array[i]);
        }
    }
}

void SimSourcePluginStateManager::processElement(char *element)
{

    char *name = strtok(element, "=");
    char *value = strtok(NULL, " =");
    name[strlen(name) - 1] = '\0';

    if (value == NULL)
        return;

    char *type = getElementDataType(name[0]);

    if (type != NULL) {

        simElement el;

        el.name = name;

        if (strncmp(type, "float", sizeof(&type)) == 0) {
            el.type = CONFIG_FLOAT;
            el.value.float_value = atof(value);
            el.length = sizeof(float);
        }
        else if (strncmp(type, "char", sizeof(&type)) == 0) {
            el.type = CONFIG_STRING;
            el.value.string_value = value;
            el.length = strlen(value);
        }
        else if (strncmp(type, "integer", sizeof(&type)) == 0) {
            el.type = CONFIG_INT;
            el.value.int_value = atoi(value);
            el.length = sizeof(int);
        }
        else if (strncmp(type, "bool", sizeof(&type)) == 0) {
            el.type = CONFIG_BOOL;
            el.length = sizeof(int);

            if (strncmp(value, "OFF", sizeof(el.value)) == 0)
                el.value.bool_value = 0;
            else
                el.value.bool_value = 1;
        }
        _enqueueCallback(this, (void *)&el, _callbackArg);
        _processedElementCount++;
    }
}

char *SimSourcePluginStateManager::getElementDataType(char identifier)
{
    switch (identifier) {
    case GAUGE_IDENTIFIER:
        return (char *)"float";
        break;
    case NUMBER_IDENTIFIER:
        return (char *)"float";
        break;
    case INDICATOR_IDENTIFIER:
        return (char *)"bool";
        break;
    case VALUE_IDENTIFIER:
        return (char *)"uint";
        break;
    case ANALOG_IDENTIFIER:
        return (char *)"char";
        break;
    case ROTARY_IDENTIFIER:
        return (char *)"char";
        break;
    case BOOLEAN_IDENTIFIER:
        return (char *)"bool";
        break;
    default:
        return NULL;
    }

    return NULL;
}

void SimSourcePluginStateManager::instanceCloseHandler(uv_handle_t *handle)
{
    if (!_eventLoop->active_handles) {
        uv_stop(_eventLoop);
    }
}

void SimSourcePluginStateManager::ceaseEventing(void)
{
    uv_stop(_eventLoop);
}

void SimSourcePluginStateManager::commenceEventing(EnqueueEventHandler enqueueCallback, void *arg)
{
    _enqueueCallback = enqueueCallback;
    _callbackArg = arg;

    // this is wrong in a number of ways - it needs to be cancel-able being its chief sin
    // TODO: unbreak
    _pluginThread = new std::thread([=] { check_uv(uv_run(_eventLoop, UV_RUN_DEFAULT)); });
}
<commit_msg>let user know of Missing prosim element data type<commit_after>#include <assert.h>
#include <iostream>
#include <memory>
#include <vector>

#include "common/simhubdeviceplugin.h"
#include "main.h"

// -- public C FFI

extern "C" {
int simplug_init(SPHANDLE *plugin_instance, LoggingFunctionCB logger)
{
    *plugin_instance = new SimSourcePluginStateManager(logger);
    return 0;
}

int simplug_config_passthrough(SPHANDLE plugin_instance, void *libconfig_instance)
{
    return static_cast<PluginStateManager *>(plugin_instance)->configPassthrough(static_cast<libconfig::Config *>(libconfig_instance));
}

int simplug_preflight_complete(SPHANDLE plugin_instance)
{
    return static_cast<PluginStateManager *>(plugin_instance)->preflightComplete();
}

void simplug_commence_eventing(SPHANDLE plugin_instance, EnqueueEventHandler enqueue_callback, void *arg)
{
    static_cast<PluginStateManager *>(plugin_instance)->commenceEventing(enqueue_callback, arg);
}

int simplug_deliver_value(SPHANDLE plugin_instance, GenericTLV *value)
{
    return static_cast<PluginStateManager *>(plugin_instance)->deliverValue(value);
}

void simplug_cease_eventing(SPHANDLE plugin_instance)
{
    static_cast<PluginStateManager *>(plugin_instance)->ceaseEventing();
}

void simplug_release(SPHANDLE plugin_instance)
{
    assert(plugin_instance);
    delete static_cast<PluginStateManager *>(plugin_instance);
}
}

// -- internal implementation

SimSourcePluginStateManager *SimSourcePluginStateManager::_StateManagerInstance = NULL;

void SimSourcePluginStateManager::AllocBuffer(uv_handle_t *handle, size_t size, uv_buf_t *buf)
{
    *buf = SimSourcePluginStateManager::StateManagerInstance()->_readBuffer;
}

//! static getter for singleton instance of our class
SimSourcePluginStateManager *SimSourcePluginStateManager::StateManagerInstance(void)
{
    return _StateManagerInstance;
}

SimSourcePluginStateManager::SimSourcePluginStateManager(LoggingFunctionCB logger)
    : PluginStateManager(logger)
{
    // enforce singleton pre-condition

    assert(!_StateManagerInstance);

    _StateManagerInstance = this;
    _processedElementCount = 0;

    if (!(_rawBuffer = (char *)malloc(BUFFER_LEN))) {
        printf("Unable to allocate buffer of size %d", BUFFER_LEN);
    }
    else {
        _readBuffer = ::uv_buf_init(_rawBuffer, BUFFER_LEN);
    }
}

SimSourcePluginStateManager::~SimSourcePluginStateManager(void)
{
    // TODO: enable once shtudown implemented
    if (_pluginThread != NULL) {
        if (_pluginThread->joinable()) {
            ceaseEventing();
            _pluginThread->join();
        }

        delete _pluginThread;
    }

    if (_rawBuffer != NULL)
        free(_rawBuffer);
}

int SimSourcePluginStateManager::preflightComplete(void)
{
    int retVal = PREFLIGHT_OK;
    int port = 8091;

    libconfig::Setting *devicesConfiguraiton = NULL;

    std::string type = "";
    std::string ipAddress = "";

    try {
        devicesConfiguraiton = &_config->lookup("configuration");
    }
    catch (const libconfig::SettingNotFoundException &nfex) {
        _logger(LOG_ERROR, "Config file parse error at %s. Skipping....", nfex.getPath());
    }

    for (libconfig::SettingIterator iter = devicesConfiguraiton->begin(); iter != devicesConfiguraiton->end(); iter++) {

        if (iter->exists("ipAddress")) {
            iter->lookupValue("ipAddress", ipAddress);
        }
        else {
            ipAddress = "127.0.0.1";
        }

        if (iter->exists("port")) {
            iter->lookupValue("port", port);
        }
    }

    struct sockaddr_in req_addr;

    _eventLoop = uv_default_loop();
    check_uv(uv_loop_init(_eventLoop));

    check_uv(uv_tcp_init(_eventLoop, &_tcpClient));
    uv_tcp_keepalive(&_tcpClient, 1, 60);

    uv_ip4_addr(ipAddress.c_str(), port, &req_addr);

    int connectErr = uv_tcp_connect(&_connectReq, &_tcpClient, (struct sockaddr *)&req_addr, &SimSourcePluginStateManager::OnConnect);

    if (connectErr < 0) {
        retVal = PREFLIGHT_FAIL;
    }

    return retVal;
}

void SimSourcePluginStateManager::OnConnect(uv_connect_t *req, int status)
{
    assert(SimSourcePluginStateManager::StateManagerInstance());

    if (status == SIM_CONNECT_NOT_FOUND) {
        SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_ERROR, "   - Failed to connect to simulator");
    }
    else {
        SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_INFO, " - Connected to simulator %d", status);
        SimSourcePluginStateManager::StateManagerInstance()->instanceConnectionHandler(req, status);
    }
}

void SimSourcePluginStateManager::OnRead(uv_stream_t *server, ssize_t nread, const uv_buf_t *buf)
{
    SimSourcePluginStateManager::StateManagerInstance()->instanceReadHandler(server, nread, buf);
}

void SimSourcePluginStateManager::OnClose(uv_handle_t *handle)
{
    assert(SimSourcePluginStateManager::StateManagerInstance());
    SimSourcePluginStateManager::StateManagerInstance()->instanceCloseHandler(handle);
}

void SimSourcePluginStateManager::instanceConnectionHandler(uv_connect_t *req, int status)
{
    if (uv_is_readable(req->handle)) {
        uv_read_start(req->handle, &SimSourcePluginStateManager::AllocBuffer, &SimSourcePluginStateManager::OnRead);
    }
    else {
        printf("not readable\n");
    }
}

void SimSourcePluginStateManager::instanceReadHandler(uv_stream_t *server, ssize_t nread, const uv_buf_t *buf)
{
    if (nread > 0) {
        uv_buf_t buffer = uv_buf_init((char *)malloc(nread), nread);
        memcpy(buffer.base, buf->base, nread);
        buffer.base[nread - 1] = '\0';
        processData(buffer.base, nread);
        free(buffer.base);
    }
    else if (nread < 0) {
        if (nread == UV_EOF) {
            SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_INFO, " - Stopping prepare3d ingest loop");
            ceaseEventing();
        }
        else {
            SimSourcePluginStateManager::StateManagerInstance()->_logger(LOG_INFO, " - %s", uv_strerror(nread));
            uv_close((uv_handle_t *)server, &SimSourcePluginStateManager::OnClose);
        }
    }
}

void SimSourcePluginStateManager::processData(char *data, int len)
{
    if (len > 2) {
        int elementCount = 0;
        char *p = strtok(data, "\n");
        char *array[MAX_ELEMENTS_PER_UPDATE];

        while (p != NULL) {
            size_t len = strlen(p);

            if (len > 2) {
                char *buffer = (char *)malloc(BUFFER_LEN);
                memset(buffer, 0, BUFFER_LEN);
                strncpy(buffer, p, len);
                buffer[len - 1] = '\0';
                array[elementCount++] = buffer;
            }

            p = strtok(NULL, "\n");
        }

        for (int i = 0; i < elementCount; ++i) {
            processElement(array[i]);
            free(array[i]);
        }
    }
}

void SimSourcePluginStateManager::processElement(char *element)
{

    char *name = strtok(element, "=");
    char *value = strtok(NULL, " =");
    name[strlen(name) - 1] = '\0';

    if (value == NULL)
        return;

    char *type = getElementDataType(name[0]);

    if (type != NULL) {

        simElement el;

        el.name = name;

        if (strncmp(type, "float", sizeof(&type)) == 0) {
            el.type = CONFIG_FLOAT;
            el.value.float_value = atof(value);
            el.length = sizeof(float);
        }
        else if (strncmp(type, "char", sizeof(&type)) == 0) {
            el.type = CONFIG_STRING;
            el.value.string_value = value;
            el.length = strlen(value);
        }
        else if (strncmp(type, "integer", sizeof(&type)) == 0) {
            el.type = CONFIG_INT;
            el.value.int_value = atoi(value);
            el.length = sizeof(int);
        }
        else if (strncmp(type, "bool", sizeof(&type)) == 0) {
            el.type = CONFIG_BOOL;
            el.length = sizeof(int);

            if (strncmp(value, "OFF", sizeof(el.value)) == 0)
                el.value.bool_value = 0;
            else
                el.value.bool_value = 1;
        }
        _enqueueCallback(this, (void *)&el, _callbackArg);
        _processedElementCount++;
    }
}

char *SimSourcePluginStateManager::getElementDataType(char identifier)
{
    switch (identifier) {
    case GAUGE_IDENTIFIER:
        return (char *)"float";
        break;
    case NUMBER_IDENTIFIER:
        return (char *)"float";
        break;
    case INDICATOR_IDENTIFIER:
        return (char *)"bool";
        break;
    case VALUE_IDENTIFIER:
        return (char *)"uint";
        break;
    case ANALOG_IDENTIFIER:
        return (char *)"char";
        break;
    case ROTARY_IDENTIFIER:
        return (char *)"char";
        break;
    case BOOLEAN_IDENTIFIER:
        return (char *)"bool";
        break;
    default:
        _logger(LOG_ERROR, "Missing prosim element data type %s", identifier);
        return NULL;
    }

    return NULL;
}

void SimSourcePluginStateManager::instanceCloseHandler(uv_handle_t *handle)
{
    if (!_eventLoop->active_handles) {
        uv_stop(_eventLoop);
    }
}

void SimSourcePluginStateManager::ceaseEventing(void)
{
    uv_stop(_eventLoop);
}

void SimSourcePluginStateManager::commenceEventing(EnqueueEventHandler enqueueCallback, void *arg)
{
    _enqueueCallback = enqueueCallback;
    _callbackArg = arg;

    // this is wrong in a number of ways - it needs to be cancel-able being its chief sin
    // TODO: unbreak
    _pluginThread = new std::thread([=] { check_uv(uv_run(_eventLoop, UV_RUN_DEFAULT)); });
}
<|endoftext|>