<commit_before>/*
 * FogLAMP process class
 *
 * Copyright (c) 2018 Dianomic Systems
 *
 * Released under the Apache 2.0 Licence
 *
 * Author: Massimiliano Pinto
 */

#include <sending.h>
#include <condition_variable>
#include <reading_set.h>
#include <plugin_manager.h>
#include <plugin_api.h>
#include <plugin.h>

/**
 * The sending process is run according to a schedule in order to send reading data
 * to the historian, e.g. the PI system.
 * It’s role is to implement the rules as to what needs to be sent and when,
 * extract the data from the storage subsystem and stream it to the north
 * for sending to the external system.
 * The sending process does not implement the protocol used to send the data,
 * that is devolved to the translation plugin in order to allow for flexibility
 * in the translation process.
 */

#define TASK_FETCH_SLEEP 500
#define TASK_SEND_SLEEP 500
#define TASK_SLEEP_MAX_INCREMENTS 4 // Currently not used

using namespace std;
using namespace std::chrono;

// Mutex for m_buffer access
mutex      readMutex;
// Mutex for thread idle time
mutex	waitMutex;
// Block the calling thread until notified to resume.
condition_variable cond_var;

// Used to identifies logs
const string LOG_SERVICE_NAME = "SendingProcess/sending_process";

// Load data from storage
static void loadDataThread(SendingProcess *loadData);
// Send data from historian
static void sendDataThread(SendingProcess *sendData);

int main(int argc, char** argv)
{
	try
	{
                // Instantiate SendingProcess class
		SendingProcess sendingProcess(argc, argv);

		// Launch the load thread
		sendingProcess.m_thread_load = new thread(loadDataThread, &sendingProcess);
		// Launch the send thread
		sendingProcess.m_thread_send = new thread(sendDataThread, &sendingProcess);

		// Run: max execution time or caught signals can stop it
		sendingProcess.run();

		// End processing
		sendingProcess.stop();
	}
	catch (const std::exception& e)
	{
		cerr << "Exception in " << argv[0] << " : " << e.what() << endl;
		// Return failure for class instance/configuration etc
		exit(1);
	}
	// Catch all exceptions
	catch (...)
	{
		std::exception_ptr p = std::current_exception();
		string name = (p ? p.__cxa_exception_type()->name() : "null");
		cerr << "Generic Exception in " << argv[0] << " : " << name << endl;
		exit(1);
	}

	// Return success
	exit(0);
}

/**
 * Apply load filter
 *
 * Just call "ingest" methid of the first one
 *
 * @param loadData    pointer to SendingProcess instance
 * @param readingSet  The current reading set loaded from storage
 */
void applyFilters(SendingProcess* loadData,
		  ReadingSet* readingSet)
{
	// Get first filter
	auto it = loadData->getFilters().begin();
	// Call first filter "ingest"
	// Note:
	// next filters will be automatically called
	(*it)->ingest(readingSet);
}

/**
 * Thread to load data from the storage layer.
 *
 * @param loadData    pointer to SendingProcess instance
 */
static void loadDataThread(SendingProcess *loadData)
{
        unsigned int    readIdx = 0;

	// Read from the storage last Id already sent
	loadData->setLastFetchId(loadData->getLastSentId());

	while (loadData->isRunning())
        {
                if (readIdx >= DATA_BUFFER_ELMS)
                {
                        readIdx = 0;
                }

		/**
		 * Check whether m_buffer[readIdx] is NULL or contains a ReadingSet
		 *
		 * Access is protected by a mutex.
		 */
                readMutex.lock();
                ReadingSet *canLoad = loadData->m_buffer.at(readIdx);
                readMutex.unlock();

                if (canLoad)
                {
			Logger::getLogger()->info("SendingProcess loadDataThread: "
						  "('%s' stream id %d), readIdx %u, buffer is NOT empty, waiting ...",
						  loadData->getDataSourceType().c_str(),
						  loadData->getStreamId(),
						  readIdx);

			if (loadData->isRunning()) {

				// Load thread is put on hold, only if the execution should proceed
				unique_lock<mutex> lock(waitMutex);
				cond_var.wait(lock);
			}
                }
                else
                {
                        // Load data from storage client (id >= lastId and getReadBlockSize() rows)
			ReadingSet* readings = NULL;
			try
			{
				bool isReading = !loadData->getDataSourceType().compare("statistics") ? false : true;
				//high_resolution_clock::time_point t1 = high_resolution_clock::now();
				if (isReading)
				{
					// Read from storage all readings with id > last sent id
					unsigned long lastReadId = loadData->getLastFetchId() + 1;
					readings = loadData->getStorageClient()->readingFetch(lastReadId,
											      loadData->getReadBlockSize());
				}
				else
				{
					// SELECT id,
					//	  key AS asset_code,
					//	  key AS read_key,
					//	  ts,
					//	  history_ts AS user_ts,
					//	  value
					// FROM statistic_history
					// WHERE id > lastId
					// ORDER BY ID ASC
					// LIMIT blockSize
					const Condition conditionId(GreaterThan);
					// WHERE id > lastId
					Where* wId = new Where("id",
								conditionId,
								to_string(loadData->getLastFetchId()));
					vector<Returns *> columns;
					// Add colums and needed aliases
					columns.push_back(new Returns("id"));
					columns.push_back(new Returns("key", "asset_code"));
					columns.push_back(new Returns("key", "read_key"));
					columns.push_back(new Returns("ts"));
					columns.push_back(new Returns("history_ts", "user_ts"));
					columns.push_back(new Returns("value"));
					// Build the query with fields, aliases and where
					Query qStatistics(columns, wId);
					// Set limit
					qStatistics.limit(loadData->getReadBlockSize());
					// Set sort
					Sort* sort = new Sort("id");
					qStatistics.sort(sort);

					// Query the statistics_history tbale and get a ReadingSet result
					readings = loadData->getStorageClient()->queryTableToReadings("statistics_history",
												      qStatistics);
				}
				//high_resolution_clock::time_point t2 = high_resolution_clock::now();
				//auto duration = duration_cast<microseconds>( t2 - t1 ).count();
			}
			catch (ReadingSetException* e)
			{
				Logger::getLogger()->error("SendingProcess loadData(): ReadingSet Exception '%s'", e->what());
			}
			catch (std::exception& e)
			{
				Logger::getLogger()->error("SendingProcess loadData(): Generic Exception: '%s'", e.what());
			}

			// Data fetched from storage layer
			if (readings != NULL && readings->getCount())
			{
				//Update last fetched reading Id
				loadData->setLastFetchId(readings->getLastId());

				/**
				 * The buffer access is protected by a mutex
				 */
                	        readMutex.lock();

				/**
				 * Set now the buffer at index to ReadingSet pointer
				 * Note: the ReadingSet pointer will be deleted by
				 * - the sending thread when processin it
				 * OR
				 * at program exit by a cleanup routine
				 *
				 * Note: the readings set can be optionally filtered
				 * if plugin filters are set.
				 */

				// Apply filters to the reading set
				if (loadData->getFiltersCount())
				{
					// Make the load readIdx available to filters
					loadData->setLoadBufferIndex(readIdx);
					// Apply filters
					applyFilters(loadData, readings);
				}
				else
				{
					// No filters: just set buffer with current data
              				loadData->m_buffer.at(readIdx) = readings;
				}

                        	readMutex.unlock();

                        	readIdx++;

				// Unlock the sendData thread
				unique_lock<mutex> lock(waitMutex);
				cond_var.notify_one();
			}
			else
			{
				// Free empty result set
				if (readings)
				{
					delete readings;
				}
				// Error or no data read: just wait
				// TODO: add increments from 1 to TASK_SLEEP_MAX_INCREMENTS
				this_thread::sleep_for(chrono::milliseconds(TASK_FETCH_SLEEP));
			}
                }
        }

	Logger::getLogger()->info("SendingProcess loadData thread: Last ID '%s' read is %lu",
				  loadData->getDataSourceType().c_str(),
				  loadData->getLastFetchId());

	/**
	 * The loop is over: unlock the sendData thread
	 */
	unique_lock<mutex> lock(waitMutex);
	cond_var.notify_one();
}

/**
 * Thread to send data to historian service
 *
 * @param loadData    pointer to SendingProcess instance
 */
static void sendDataThread(SendingProcess *sendData)
{
	unsigned long totSent = 0;
	unsigned int  sendIdx = 0;

        while (sendData->isRunning())
        {
                if (sendIdx >= DATA_BUFFER_ELMS)
		{

			if (sendData->getUpdateDb())
			{
				// Update counters to Database
				sendData->updateDatabaseCounters();

				// numReadings sent so far
				totSent = sendData->getSentReadings();

				// Reset current sent readings
				sendData->resetSentReadings();

				// DB update done
				sendData->setUpdateDb(false);
                        }

			// Reset send index
			sendIdx = 0;
		}

		/*
		 * Check whether m_buffer[sendIdx] is NULL or contains ReadinSet data.
		 * Access is protected by a mutex.
		 */
                readMutex.lock();
                ReadingSet *canSend = sendData->m_buffer.at(sendIdx);
                readMutex.unlock();

                if (canSend == NULL)
                {
                        /*Logger::getLogger()->info("SendingProcess sendDataThread: " \
                                                  "('%s' stream id %d), sendIdx %u, buffer is empty, waiting ...",
						  sendData->getDataSourceType().c_str(),
                                                  sendData->getStreamId(),
                                                  sendIdx);*/

			if (sendData->getUpdateDb())
			{
                                // Update counters to Database
				sendData->updateDatabaseCounters();

				// numReadings sent so far
				totSent = sendData->getSentReadings();

				// Reset current sent readings
				sendData->resetSentReadings();

				// DB update done
				sendData->setUpdateDb(false);
			}

			if (sendData->isRunning()) {

				// Send thread is put on hold, only if the execution shoule proceed
				unique_lock<mutex> lock(waitMutex);
				cond_var.wait(lock);
			}
                }
                else
                {
			/**
			 * Send the buffer content ( const vector<Readings *>& )
			 * to historian server via m_plugin->send(data).
			 * Readings data by getAllReadings() will be
			 * transformed using historian protocol and then sent to destination.
			 */

			const vector<Reading *> &readingData = sendData->m_buffer.at(sendIdx)->getAllReadings();

			uint32_t sentReadings = sendData->m_plugin->send(readingData);

			if (sentReadings)
			{
				/** Sending done */
				sendData->setUpdateDb(true);

				/**
				 * 1- emptying data in m_buffer[sendIdx].
				 * The buffer access is protected by a mutex.
				 */
				readMutex.lock();

				// Update last sent reading Id
				sendData->setLastSentId(readingData.back()->getId());

				delete sendData->m_buffer.at(sendIdx);
				sendData->m_buffer.at(sendIdx) = NULL;

				/** 2- Update sent counter (memory only) */
				sendData->updateSentReadings(sentReadings);

				// numReadings sent so far
				totSent = sendData->getSentReadings();

				readMutex.unlock();

				sendIdx++;

				// Unlock the loadData thread
				unique_lock<mutex> lock(waitMutex);
				cond_var.notify_one();
			}
			else
			{
				Logger::getLogger()->error("SendingProcess sendDataThread: Error while sending" \
							   "('%s' stream id %d), sendIdx %u. N. (%d readings)",
							   sendData->getDataSourceType().c_str(),
							   sendData->getStreamId(),
							   sendIdx,
							   sendData->m_buffer[sendIdx]->getCount());

				if (sendData->getUpdateDb())
				{
					// Update counters to Database
					sendData->updateDatabaseCounters();

					// numReadings sent so far
					totSent = sendData->getSentReadings();

					// Reset current sent readings
					sendData->resetSentReadings();

					// DB update done
					sendData->setUpdateDb(false);
				}

				// Error: just wait & continue
				// TODO: add increments from 1 to TASK_SLEEP_MAX_INCREMENTS
				this_thread::sleep_for(chrono::milliseconds(TASK_SEND_SLEEP));
			}
                }
        }
	Logger::getLogger()->info("SendingProcess sendData thread: sent %lu total '%s'",
				  totSent,
				  sendData->getDataSourceType().c_str());

	if (sendData->getUpdateDb())
	{
                // Update counters to Database
		sendData->updateDatabaseCounters();

                // numReadings sent so far
		totSent = sendData->getSentReadings();

                // Reset current sent readings
		sendData->resetSentReadings();

                sendData->setUpdateDb(false);
        }

	/**
	 * The loop is over: unlock the loadData thread
	 */
	unique_lock<mutex> lock(waitMutex);
	cond_var.notify_one();
}
<commit_msg>FOGL-1955: improved handling of totSent<commit_after>/*
 * FogLAMP process class
 *
 * Copyright (c) 2018 Dianomic Systems
 *
 * Released under the Apache 2.0 Licence
 *
 * Author: Massimiliano Pinto
 */

#include <sending.h>
#include <condition_variable>
#include <reading_set.h>
#include <plugin_manager.h>
#include <plugin_api.h>
#include <plugin.h>

/**
 * The sending process is run according to a schedule in order to send reading data
 * to the historian, e.g. the PI system.
 * It’s role is to implement the rules as to what needs to be sent and when,
 * extract the data from the storage subsystem and stream it to the north
 * for sending to the external system.
 * The sending process does not implement the protocol used to send the data,
 * that is devolved to the translation plugin in order to allow for flexibility
 * in the translation process.
 */

#define TASK_FETCH_SLEEP 500
#define TASK_SEND_SLEEP 500
#define TASK_SLEEP_MAX_INCREMENTS 4 // Currently not used

using namespace std;
using namespace std::chrono;

// Mutex for m_buffer access
mutex      readMutex;
// Mutex for thread idle time
mutex	waitMutex;
// Block the calling thread until notified to resume.
condition_variable cond_var;

// Used to identifies logs
const string LOG_SERVICE_NAME = "SendingProcess/sending_process";

// Load data from storage
static void loadDataThread(SendingProcess *loadData);
// Send data from historian
static void sendDataThread(SendingProcess *sendData);

int main(int argc, char** argv)
{
	try
	{
                // Instantiate SendingProcess class
		SendingProcess sendingProcess(argc, argv);

		// Launch the load thread
		sendingProcess.m_thread_load = new thread(loadDataThread, &sendingProcess);
		// Launch the send thread
		sendingProcess.m_thread_send = new thread(sendDataThread, &sendingProcess);

		// Run: max execution time or caught signals can stop it
		sendingProcess.run();

		// End processing
		sendingProcess.stop();
	}
	catch (const std::exception& e)
	{
		cerr << "Exception in " << argv[0] << " : " << e.what() << endl;
		// Return failure for class instance/configuration etc
		exit(1);
	}
	// Catch all exceptions
	catch (...)
	{
		std::exception_ptr p = std::current_exception();
		string name = (p ? p.__cxa_exception_type()->name() : "null");
		cerr << "Generic Exception in " << argv[0] << " : " << name << endl;
		exit(1);
	}

	// Return success
	exit(0);
}

/**
 * Apply load filter
 *
 * Just call "ingest" methid of the first one
 *
 * @param loadData    pointer to SendingProcess instance
 * @param readingSet  The current reading set loaded from storage
 */
void applyFilters(SendingProcess* loadData,
		  ReadingSet* readingSet)
{
	// Get first filter
	auto it = loadData->getFilters().begin();
	// Call first filter "ingest"
	// Note:
	// next filters will be automatically called
	(*it)->ingest(readingSet);
}

/**
 * Thread to load data from the storage layer.
 *
 * @param loadData    pointer to SendingProcess instance
 */
static void loadDataThread(SendingProcess *loadData)
{
        unsigned int    readIdx = 0;

	// Read from the storage last Id already sent
	loadData->setLastFetchId(loadData->getLastSentId());

	while (loadData->isRunning())
        {
                if (readIdx >= DATA_BUFFER_ELMS)
                {
                        readIdx = 0;
                }

		/**
		 * Check whether m_buffer[readIdx] is NULL or contains a ReadingSet
		 *
		 * Access is protected by a mutex.
		 */
                readMutex.lock();
                ReadingSet *canLoad = loadData->m_buffer.at(readIdx);
                readMutex.unlock();

                if (canLoad)
                {
			Logger::getLogger()->info("SendingProcess loadDataThread: "
						  "('%s' stream id %d), readIdx %u, buffer is NOT empty, waiting ...",
						  loadData->getDataSourceType().c_str(),
						  loadData->getStreamId(),
						  readIdx);

			if (loadData->isRunning()) {

				// Load thread is put on hold, only if the execution should proceed
				unique_lock<mutex> lock(waitMutex);
				cond_var.wait(lock);
			}
                }
                else
                {
                        // Load data from storage client (id >= lastId and getReadBlockSize() rows)
			ReadingSet* readings = NULL;
			try
			{
				bool isReading = !loadData->getDataSourceType().compare("statistics") ? false : true;
				//high_resolution_clock::time_point t1 = high_resolution_clock::now();
				if (isReading)
				{
					// Read from storage all readings with id > last sent id
					unsigned long lastReadId = loadData->getLastFetchId() + 1;
					readings = loadData->getStorageClient()->readingFetch(lastReadId,
											      loadData->getReadBlockSize());
				}
				else
				{
					// SELECT id,
					//	  key AS asset_code,
					//	  key AS read_key,
					//	  ts,
					//	  history_ts AS user_ts,
					//	  value
					// FROM statistic_history
					// WHERE id > lastId
					// ORDER BY ID ASC
					// LIMIT blockSize
					const Condition conditionId(GreaterThan);
					// WHERE id > lastId
					Where* wId = new Where("id",
								conditionId,
								to_string(loadData->getLastFetchId()));
					vector<Returns *> columns;
					// Add colums and needed aliases
					columns.push_back(new Returns("id"));
					columns.push_back(new Returns("key", "asset_code"));
					columns.push_back(new Returns("key", "read_key"));
					columns.push_back(new Returns("ts"));
					columns.push_back(new Returns("history_ts", "user_ts"));
					columns.push_back(new Returns("value"));
					// Build the query with fields, aliases and where
					Query qStatistics(columns, wId);
					// Set limit
					qStatistics.limit(loadData->getReadBlockSize());
					// Set sort
					Sort* sort = new Sort("id");
					qStatistics.sort(sort);

					// Query the statistics_history tbale and get a ReadingSet result
					readings = loadData->getStorageClient()->queryTableToReadings("statistics_history",
												      qStatistics);
				}
				//high_resolution_clock::time_point t2 = high_resolution_clock::now();
				//auto duration = duration_cast<microseconds>( t2 - t1 ).count();
			}
			catch (ReadingSetException* e)
			{
				Logger::getLogger()->error("SendingProcess loadData(): ReadingSet Exception '%s'", e->what());
			}
			catch (std::exception& e)
			{
				Logger::getLogger()->error("SendingProcess loadData(): Generic Exception: '%s'", e.what());
			}

			// Data fetched from storage layer
			if (readings != NULL && readings->getCount())
			{
				//Update last fetched reading Id
				loadData->setLastFetchId(readings->getLastId());

				/**
				 * The buffer access is protected by a mutex
				 */
                	        readMutex.lock();

				/**
				 * Set now the buffer at index to ReadingSet pointer
				 * Note: the ReadingSet pointer will be deleted by
				 * - the sending thread when processin it
				 * OR
				 * at program exit by a cleanup routine
				 *
				 * Note: the readings set can be optionally filtered
				 * if plugin filters are set.
				 */

				// Apply filters to the reading set
				if (loadData->getFiltersCount())
				{
					// Make the load readIdx available to filters
					loadData->setLoadBufferIndex(readIdx);
					// Apply filters
					applyFilters(loadData, readings);
				}
				else
				{
					// No filters: just set buffer with current data
              				loadData->m_buffer.at(readIdx) = readings;
				}

                        	readMutex.unlock();

                        	readIdx++;

				// Unlock the sendData thread
				unique_lock<mutex> lock(waitMutex);
				cond_var.notify_one();
			}
			else
			{
				// Free empty result set
				if (readings)
				{
					delete readings;
				}
				// Error or no data read: just wait
				// TODO: add increments from 1 to TASK_SLEEP_MAX_INCREMENTS
				this_thread::sleep_for(chrono::milliseconds(TASK_FETCH_SLEEP));
			}
                }
        }

	Logger::getLogger()->info("SendingProcess loadData thread: Last ID '%s' read is %lu",
				  loadData->getDataSourceType().c_str(),
				  loadData->getLastFetchId());

	/**
	 * The loop is over: unlock the sendData thread
	 */
	unique_lock<mutex> lock(waitMutex);
	cond_var.notify_one();
}

/**
 * Thread to send data to historian service
 *
 * @param loadData    pointer to SendingProcess instance
 */
static void sendDataThread(SendingProcess *sendData)
{
	unsigned int  sendIdx = 0;
	sendData->resetSentReadings();

	while (sendData->isRunning())
        {
                if (sendIdx >= DATA_BUFFER_ELMS)
		{

			if (sendData->getUpdateDb())
			{
				// Update counters to Database
				sendData->updateDatabaseCounters();

				// DB update done
				sendData->setUpdateDb(false);
                        }

			// Reset send index
			sendIdx = 0;
		}

		/*
		 * Check whether m_buffer[sendIdx] is NULL or contains ReadinSet data.
		 * Access is protected by a mutex.
		 */
                readMutex.lock();
                ReadingSet *canSend = sendData->m_buffer.at(sendIdx);
                readMutex.unlock();

                if (canSend == NULL)
                {
                        /*Logger::getLogger()->info("SendingProcess sendDataThread: " \
                                                  "('%s' stream id %d), sendIdx %u, buffer is empty, waiting ...",
						  sendData->getDataSourceType().c_str(),
                                                  sendData->getStreamId(),
                                                  sendIdx);*/

			if (sendData->getUpdateDb())
			{
                                // Update counters to Database
				sendData->updateDatabaseCounters();

				// DB update done
				sendData->setUpdateDb(false);
			}

			if (sendData->isRunning()) {

				// Send thread is put on hold, only if the execution shoule proceed
				unique_lock<mutex> lock(waitMutex);
				cond_var.wait(lock);
			}
                }
                else
                {
			/**
			 * Send the buffer content ( const vector<Readings *>& )
			 * to historian server via m_plugin->send(data).
			 * Readings data by getAllReadings() will be
			 * transformed using historian protocol and then sent to destination.
			 */

			const vector<Reading *> &readingData = sendData->m_buffer.at(sendIdx)->getAllReadings();

			uint32_t sentReadings = sendData->m_plugin->send(readingData);

			if (sentReadings)
			{
				/** Sending done */
				sendData->setUpdateDb(true);

				/**
				 * 1- emptying data in m_buffer[sendIdx].
				 * The buffer access is protected by a mutex.
				 */
				readMutex.lock();

				// Update last sent reading Id
				sendData->setLastSentId(readingData.back()->getId());

				delete sendData->m_buffer.at(sendIdx);
				sendData->m_buffer.at(sendIdx) = NULL;

				/** 2- Update sent counter (memory only) */
				sendData->updateSentReadings(sentReadings);

				readMutex.unlock();

				sendIdx++;

				// Unlock the loadData thread
				unique_lock<mutex> lock(waitMutex);
				cond_var.notify_one();
			}
			else
			{
				Logger::getLogger()->error("SendingProcess sendDataThread: Error while sending" \
							   "('%s' stream id %d), sendIdx %u. N. (%d readings)",
							   sendData->getDataSourceType().c_str(),
							   sendData->getStreamId(),
							   sendIdx,
							   sendData->m_buffer[sendIdx]->getCount());

				if (sendData->getUpdateDb())
				{
					// Update counters to Database
					sendData->updateDatabaseCounters();

					// DB update done
					sendData->setUpdateDb(false);
				}

				// Error: just wait & continue
				// TODO: add increments from 1 to TASK_SLEEP_MAX_INCREMENTS
				this_thread::sleep_for(chrono::milliseconds(TASK_SEND_SLEEP));
			}
                }
        }
	Logger::getLogger()->info("SendingProcess sendData thread: sent %lu total '%s'",
				  sendData->getSentReadings(),
				  sendData->getDataSourceType().c_str());

	if (sendData->getUpdateDb())
	{
                // Update counters to Database
		sendData->updateDatabaseCounters();

                sendData->setUpdateDb(false);
        }

	/**
	 * The loop is over: unlock the loadData thread
	 */
	unique_lock<mutex> lock(waitMutex);
	cond_var.notify_one();
}
<|endoftext|>


<commit_before>
#ifdef _DEBUG

#include "AnimationSample.h"

AnimationSample::AnimationSample()
{
	m_Animation = NNAnimation::Create( 6, L"Sprite/attack_0.png",
										L"Sprite/attack_1.png",
										L"Sprite/die_0.png",
										L"Sprite/die_1.png",
										L"Sprite/idle_0.png",
										L"Sprite/idle_1.png");

	m_Animation->SetPosition( NNPoint(50.f,50.f) );

	AddChild( m_Animation );
}
AnimationSample::~AnimationSample()
{

}

void AnimationSample::Render()
{
	NNObject::Render();
}
void AnimationSample::Update( float eTime )
{
	NNObject::Update( eTime );
}

#endif<commit_msg>* NNObject:: -> NNScene::<commit_after>
#ifdef _DEBUG

#include "AnimationSample.h"

AnimationSample::AnimationSample()
{
	m_Animation = NNAnimation::Create( 6, L"Sprite/attack_0.png",
										L"Sprite/attack_1.png",
										L"Sprite/die_0.png",
										L"Sprite/die_1.png",
										L"Sprite/idle_0.png",
										L"Sprite/idle_1.png");

	m_Animation->SetPosition( NNPoint(50.f,50.f) );

	AddChild( m_Animation );
}
AnimationSample::~AnimationSample()
{

}

void AnimationSample::Render()
{
	NNScene::Render();
}
void AnimationSample::Update( float eTime )
{
	NNScene::Update( eTime );
}

#endif<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: util.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2005-03-29 13:28:15 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "util.hxx"

#include <com/sun/star/registry/XImplementationRegistration.hpp>
#include <com/sun/star/security/KeyUsage.hpp>
#include <cppuhelper/bootstrap.hxx>
#include <xmlsecurity/biginteger.hxx>
#include <comphelper/processfactory.hxx>

#include <rtl/ustrbuf.hxx>

#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

//CP : added by CP
#include <rtl/locale.h>
#include <osl/nlsupport.h>

#ifndef _OSL_PROCESS_H_
#include <osl/process.h>
#endif

//CP : end

namespace cssu = com::sun::star::uno;
namespace cssl = com::sun::star::lang;
namespace cssxc = com::sun::star::xml::crypto;
namespace cssi = com::sun::star::io;

/** convert util::DateTime to ISO Date String */
void convertDateTime( ::rtl::OUStringBuffer& rBuffer,
    const com::sun::star::util::DateTime& rDateTime )
{
    String aString( String::CreateFromInt32( rDateTime.Year ) );
    aString += '-';
    if( rDateTime.Month < 10 )
        aString += '0';
    aString += String::CreateFromInt32( rDateTime.Month );
    aString += '-';
    if( rDateTime.Day < 10 )
        aString += '0';
    aString += String::CreateFromInt32( rDateTime.Day );

    if( rDateTime.Seconds != 0 ||
        rDateTime.Minutes != 0 ||
        rDateTime.Hours   != 0 )
    {
        aString += 'T';
        if( rDateTime.Hours < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Hours );
        aString += ':';
        if( rDateTime.Minutes < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Minutes );
        aString += ':';
        if( rDateTime.Seconds < 10 )
            aString += '0';
        aString += String::CreateFromInt32( rDateTime.Seconds );
        if ( rDateTime.HundredthSeconds > 0)
        {
            aString += ',';
            if (rDateTime.HundredthSeconds < 10)
                aString += '0';
            aString += String::CreateFromInt32( rDateTime.HundredthSeconds );
        }
    }

    rBuffer.append( aString );
}

::rtl::OUString printHexString(cssu::Sequence< sal_Int8 > data)
{
    int length = data.getLength();
    ::rtl::OUString result;

    char number[4];
    for (int j=0; j<length; j++)
    {
        sprintf(number, "%02X ", (unsigned char)data[j]);
        result += rtl::OUString::createFromAscii( number );
    }

    return result;
}

cssu::Reference< cssl::XMultiServiceFactory > serviceManager(
    cssu::Reference< cssu::XComponentContext > &xContext,
    rtl::OUString sUnoUrl,
    rtl::OUString sRdbUrl )
    throw( cssu::RuntimeException , cssu::Exception )
{
    cssu::Reference< cssl::XMultiComponentFactory > xLocalServiceManager = NULL ;
    cssu::Reference< cssu::XComponentContext > xLocalComponentContext = NULL ;

    cssu::Reference< ::com::sun::star::registry::XSimpleRegistry > xSimpleRegistry
        = ::cppu::createSimpleRegistry();
    OSL_ENSURE( xSimpleRegistry.is(),
        "serviceManager - "
        "Cannot create simple registry" ) ;

    xSimpleRegistry->open(sRdbUrl, sal_True, sal_False);
    OSL_ENSURE( xSimpleRegistry->isValid() ,
        "serviceManager - "
        "Cannot open xml security registry rdb" ) ;

    xLocalComponentContext = ::cppu::bootstrap_InitialComponentContext( xSimpleRegistry ) ;
    OSL_ENSURE( xLocalComponentContext.is() ,
        "serviceManager - "
        "Cannot create intial component context" ) ;

    xLocalServiceManager = xLocalComponentContext->getServiceManager() ;
    OSL_ENSURE( xLocalServiceManager.is() ,
        "serviceManager - "
        "Cannot create intial service manager" ) ;

    xContext = xLocalComponentContext ;
    cssu::Reference< cssl::XMultiServiceFactory > xManager = cssu::Reference< cssl::XMultiServiceFactory >(xLocalServiceManager, cssu::UNO_QUERY) ;

    ::comphelper::setProcessServiceFactory( xManager );

    return xManager;
}

::rtl::OUString getSignatureInformation(
    const SignatureInformation& infor,
    cssu::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >& xSecurityEnvironment )
{
    char* status[50] = {
        "STATUS_UNKNOWN",
        "OPERATION_SUCCEEDED",
        "RUNTIMEERROR_FAILED",
        "ENGINE_FAILED",
        "MALLOC_FAILED",
        "STRDUP_FAILED",
        "CRYPTO_FAILED",
        "XML_FAILED",
        "XSLT_FAILED",
        "IO_FAILED",
        "DISABLED",
        "NOT_IMPLEMENTED",
        "INVALID_SIZE",
        "INVALID_DATA",
        "INVALID_RESULT",
        "INVALID_TYPE",
        "INVALID_OPERATION",
        "INVALID_STATUS",
        "INVALID_FORMAT",
        "DATA_NOT_MATCH",
        "INVALID_NODE",
        "INVALID_NODE_CONTENT",
        "INVALID_NODE_ATTRIBUTE",
        "MISSING_NODE_ATTRIBUTE",
        "NODE_ALREADY_PRESENT",
        "UNEXPECTED_NODE",
        "NODE_NOT_FOUND",
        "INVALID_TRANSFORM",
        "INVALID_TRANSFORM_KEY",
        "INVALID_URI_TYPE",
        "TRANSFORM_SAME_DOCUMENT_REQUIRED",
        "TRANSFORM_DISABLED",
        "INVALID_KEY_DATA",
        "KEY_DATA_NOT_FOUND",
        "KEY_DATA_ALREADY_EXIST",
        "INVALID_KEY_DATA_SIZE",
        "KEY_NOT_FOUND",
        "KEYDATA_DISABLED",
        "MAX_RETRIEVALS_LEVEL",
        "MAX_RETRIEVAL_TYPE_MISMATCH",
        "MAX_ENCKEY_LEVEL",
        "CERT_VERIFY_FAILED",
        "CERT_NOT_FOUND",
        "CERT_REVOKED",
        "CERT_ISSUER_FAILED",
        "CERT_NOT_YET_VALID",
        "CERT_HAS_EXPIRED",
        "DSIG_NO_REFERENCES",
        "DSIG_INVALID_REFERENCE",
        "ASSERTION"};

    //char* status[5]={"INIT", "CREATION_SUCCEED", "CREATION_FAIL", "VERIFY_SUCCEED", "VERIFY_FAIL"};

    rtl::OUString result;

    result += rtl::OUString::createFromAscii( "Security Id : " )
        +rtl::OUString::valueOf(infor.nSecurityId)
        +rtl::OUString::createFromAscii( "\n" );
    result += rtl::OUString::createFromAscii( "Status : [" )
        +rtl::OUString::valueOf((sal_Int32)(infor.nStatus))
        +rtl::OUString::createFromAscii( "] " )
        +rtl::OUString::createFromAscii(status[infor.nStatus])
        +rtl::OUString::createFromAscii( "\n" );

    const SignatureReferenceInformations& rInfors = infor.vSignatureReferenceInfors;
    int i;
    int size = rInfors.size();

    result += rtl::OUString::createFromAscii( "--References :\n" );
    for (i=0; i<size; i++)
    {
            result += rtl::OUString::createFromAscii( "---URI : " );
        result += rInfors[i].ouURI;
        result += rtl::OUString::createFromAscii( "\n" );
            result += rtl::OUString::createFromAscii( "---DigestValue : " );
        result += rInfors[i].ouDigestValue;
        result += rtl::OUString::createFromAscii( "\n" );
    }

        if (infor.ouX509IssuerName.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509IssuerName :\n" );
            result += infor.ouX509IssuerName;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouX509SerialNumber.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509SerialNumber :\n" );
            result += infor.ouX509SerialNumber;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouX509Certificate.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--X509Certificate :\n" );
            result += infor.ouX509Certificate;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouSignatureValue.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--SignatureValue :\n" );
            result += infor.ouSignatureValue;
            result += rtl::OUString::createFromAscii( "\n" );
        }

           result += rtl::OUString::createFromAscii( "--Date :\n" );

    ::rtl::OUStringBuffer buffer;
    convertDateTime( buffer, infor.stDateTime );
    result += buffer.makeStringAndClear();
           result += rtl::OUString::createFromAscii( "\n" );

        /*
        if (infor.ouDate.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--Date :\n" );
            result += infor.ouDate;
            result += rtl::OUString::createFromAscii( "\n" );
        }

        if (infor.ouTime.getLength()>0)
        {
            result += rtl::OUString::createFromAscii( "--Time :\n" );
            result += infor.ouTime;
            result += rtl::OUString::createFromAscii( "\n" );
        }
        */

        if (infor.ouX509IssuerName.getLength()>0 && infor.ouX509SerialNumber.getLength()>0 && xSecurityEnvironment.is())
        {
            result += rtl::OUString::createFromAscii( "--Certificate Path :\n" );
            cssu::Reference< ::com::sun::star::security::XCertificate > xCert = xSecurityEnvironment->getCertificate( infor.ouX509IssuerName, numericStringToBigInteger(infor.ouX509SerialNumber) );
            cssu::Sequence < cssu::Reference< ::com::sun::star::security::XCertificate > > xCertPath;
            if(! xCert.is() )
            {
                fprintf(stdout , " xCert is NULL , so can not buildCertificatePath\n");
                return result ;
            }
            else
            {
                xCertPath = xSecurityEnvironment->buildCertificatePath( xCert ) ;
            }

        for( int i = 0; i < xCertPath.getLength(); i++ )
        {
            result += xCertPath[i]->getSubjectName();
                    result += rtl::OUString::createFromAscii( "\n    Subject public key algorithm : " );
                    result += xCertPath[i]->getSubjectPublicKeyAlgorithm();
                    result += rtl::OUString::createFromAscii( "\n    Signature algorithm : " );
                    result += xCertPath[i]->getSignatureAlgorithm();

                    result += rtl::OUString::createFromAscii( "\n    Subject public key value : " );
                    cssu::Sequence< sal_Int8 > keyValue = xCertPath[i]->getSubjectPublicKeyValue();
                    result += printHexString(keyValue);

                    result += rtl::OUString::createFromAscii( "\n    Thumbprint (SHA1) : " );
                    cssu::Sequence< sal_Int8 > SHA1Thumbprint = xCertPath[i]->getSHA1Thumbprint();
                    result += printHexString(SHA1Thumbprint);

                    result += rtl::OUString::createFromAscii( "\n    Thumbprint (MD5) : " );
                    cssu::Sequence< sal_Int8 > MD5Thumbprint = xCertPath[i]->getMD5Thumbprint();
                    result += printHexString(MD5Thumbprint);

                    result += rtl::OUString::createFromAscii( "\n  <<\n" );
        }

                   result += rtl::OUString::createFromAscii( "\n    Key Usage : " );
                   sal_Int32 usage = xCert->getCertificateUsage();

                   if (usage & ::com::sun::star::security::KeyUsage::DIGITAL_SIGNATURE)
                   {
                       result += rtl::OUString::createFromAscii( "DIGITAL_SIGNATURE " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::NON_REPUDIATION)
                   {
                       result += rtl::OUString::createFromAscii( "NON_REPUDIATION " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_ENCIPHERMENT)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_ENCIPHERMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::DATA_ENCIPHERMENT)
                   {
                       result += rtl::OUString::createFromAscii( "DATA_ENCIPHERMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_AGREEMENT)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_AGREEMENT " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::KEY_CERT_SIGN)
                   {
                       result += rtl::OUString::createFromAscii( "KEY_CERT_SIGN " );
                   }

                   if (usage & ::com::sun::star::security::KeyUsage::CRL_SIGN)
                   {
                       result += rtl::OUString::createFromAscii( "CRL_SIGN " );
                   }

                   result += rtl::OUString::createFromAscii( "\n" );
        }

    result += rtl::OUString::createFromAscii( "\n" );
    return result;
}

::rtl::OUString getSignatureInformations(
    const SignatureInformations& SignatureInformations,
    cssu::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecurityEnvironment )
{
    rtl::OUString result;
    int i;
    int size = SignatureInformations.size();

    for (i=0; i<size; i++)
    {
        const SignatureInformation& infor = SignatureInformations[i];
        result += getSignatureInformation( infor, xSecurityEnvironment );
    }

    result += rtl::OUString::createFromAscii( "\n" );

    return result;
}

::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >
    getCertificateFromEnvironment( ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment >  xSecurityEnvironment , BOOL nType)
{
    cssu::Sequence< cssu::Reference< ::com::sun::star::security::XCertificate > > xPersonalCerts ;
    int length = 0;
    int i;

    // add By CP
    sal_uInt16 encoding ;
    rtl_Locale *pLocale = NULL ;
    osl_getProcessLocale( &pLocale ) ;
    encoding = osl_getTextEncodingFromLocale( pLocale ) ;
    // CP end

    if( nType != FALSE )
        xPersonalCerts = xSecurityEnvironment->getPersonalCertificates() ;
    else
        return NULL; // not support then;

    length = xPersonalCerts.getLength();
    if(length == 0)
    {
        fprintf( stdout, "\nNo certificate found!\n" ) ;
        return NULL;
    }
    fprintf( stdout, "\nSelect a certificate\n" ) ;
    fprintf( stdout, "================================================================================\n" ) ;
    for( i = 0; i < length; i ++ )
    {
        rtl::OUString xxxIssuer;
        rtl::OUString xxxSubject;
        rtl::OString yyyIssuer;
        rtl::OString yyySubject;

        xxxIssuer=xPersonalCerts[i]->getIssuerName();
        yyyIssuer=rtl::OUStringToOString( xxxIssuer, encoding );

        xxxSubject=xPersonalCerts[i]->getSubjectName();
        yyySubject=rtl::OUStringToOString( xxxSubject, encoding );

        fprintf( stdout, "%d:issuer=[%s] subject=[%s]\n",
            i+1,
            yyyIssuer.getStr(),
            yyySubject.getStr());
    }

    fprintf( stdout, "================================================================================\n" ) ;

    bool bInvalid = false;
    int sel = 0;
    do
    {
        if (bInvalid)
        {
            fprintf( stdout, "Invalid value! \n" );
        }

        fprintf( stdout, "Select <1-%d>:", length ) ;
        fflush(stdin);
        fscanf( stdin, "%d", &sel ) ;
        bInvalid = true;
    }while(sel<1 || sel>length);
    sel--;

    return xPersonalCerts[sel] ;
}
<commit_msg>INTEGRATION: CWS xmlsec12 (1.9.6); FILE MERGED 2005/04/15 14:30:10 mt 1.9.6.3: clean-ups... 2005/04/14 17:51:29 mt 1.9.6.2: clean-ups... 2005/04/13 10:14:49 mt 1.9.6.1: Clean-Ups...<commit_after>/*************************************************************************
 *
 *  $RCSfile: util.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-05-18 10:02:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "util.hxx"

#include <stdio.h>

#include <com/sun/star/registry/XImplementationRegistration.hpp>
#include <cppuhelper/bootstrap.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/streamhelper.hxx>

#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

namespace cssu = com::sun::star::uno;
namespace cssl = com::sun::star::lang;
namespace cssxc = com::sun::star::xml::crypto;
namespace cssi = com::sun::star::io;

using namespace ::com::sun::star;

cssu::Reference< cssl::XMultiServiceFactory > CreateDemoServiceFactory()
{
    cssu::Reference< cssl::XMultiServiceFactory > xMSF;

    try
    {
        cssu::Reference< cssl::XMultiComponentFactory > xLocalServiceManager = NULL ;
        cssu::Reference< cssu::XComponentContext > xLocalComponentContext = NULL ;

        cssu::Reference< ::com::sun::star::registry::XSimpleRegistry > xSimpleRegistry
            = ::cppu::createSimpleRegistry();
        OSL_ENSURE( xSimpleRegistry.is(),
            "serviceManager - "
            "Cannot create simple registry" ) ;

        xSimpleRegistry->open(rtl::OUString::createFromAscii( "demo.rdb" ), sal_True, sal_False);
        OSL_ENSURE( xSimpleRegistry->isValid() ,
            "serviceManager - "
            "Cannot open xml security registry rdb" ) ;

        xLocalComponentContext = ::cppu::bootstrap_InitialComponentContext( xSimpleRegistry ) ;
        OSL_ENSURE( xLocalComponentContext.is() ,
            "serviceManager - "
            "Cannot create intial component context" ) ;

        xLocalServiceManager = xLocalComponentContext->getServiceManager() ;
        OSL_ENSURE( xLocalServiceManager.is() ,
            "serviceManager - "
            "Cannot create intial service manager" ) ;

        xMSF = cssu::Reference< cssl::XMultiServiceFactory >(xLocalServiceManager, cssu::UNO_QUERY) ;

        ::comphelper::setProcessServiceFactory( xMSF );
    }
    catch( cssu::Exception& e )
    {
        fprintf( stderr , "Error creating ServiceManager, Exception is %s\n" , rtl::OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US ).getStr() ) ;
        exit (-1);
    }

    return xMSF;
}

::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > OpenInputStream( const ::rtl::OUString& rStreamName )
{
    SvFileStream* pStream = new SvFileStream( rStreamName, STREAM_READ );
    pStream->Seek( STREAM_SEEK_TO_END );
    ULONG nBytes = pStream->Tell();
    pStream->Seek( STREAM_SEEK_TO_BEGIN );
    SvLockBytesRef xLockBytes = new SvLockBytes( pStream, TRUE );
    uno::Reference< io::XInputStream > xInputStream = new utl::OInputStreamHelper( xLockBytes, nBytes );

    return xInputStream;

}

::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > OpenOutputStream( const ::rtl::OUString& rStreamName )
{
    SvFileStream* pStream = new SvFileStream( rStreamName, STREAM_WRITE );
    SvLockBytesRef xLockBytes = new SvLockBytes( pStream, TRUE );
    uno::Reference< io::XOutputStream > xOutputStream = new utl::OOutputStreamHelper( xLockBytes );

    return xOutputStream;
}
<|endoftext|>


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

#include "RestAdminLogHandler.h"

#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>

#include "Basics/StringUtils.h"
#include "Logger/LogBuffer.h"
#include "Logger/Logger.h"
#include "Rest/HttpRequest.h"

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

RestAdminLogHandler::RestAdminLogHandler(HttpRequest* request)
    : RestBaseHandler(request) {}

bool RestAdminLogHandler::isDirect() const { return true; }

////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_get_admin_modules_flush
////////////////////////////////////////////////////////////////////////////////

HttpHandler::status_t RestAdminLogHandler::execute() {
  // "/log" can only be called for the _system database
  if (_request->databaseName() != "_system") {
    generateError(GeneralResponse::ResponseCode::FORBIDDEN,
                  TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE);
    return status_t(HANDLER_DONE);
  }

  // check the maximal log level to report
  bool found1;
  std::string const& upto =
      StringUtils::tolower(_request->value("upto", found1));

  bool found2;
  std::string const& lvl =
      StringUtils::tolower(_request->value("level", found2));

  LogLevel ul = LogLevel::INFO;
  bool useUpto = true;
  std::string logLevel;

  // prefer level over upto
  if (found2) {
    logLevel = lvl;
    useUpto = false;
  } else if (found1) {
    logLevel = upto;
    useUpto = true;
  }

  if (found1 || found2) {
    if (logLevel == "fatal" || logLevel == "0") {
      ul = LogLevel::FATAL;
    } else if (logLevel == "error" || logLevel == "1") {
      ul = LogLevel::ERR;
    } else if (logLevel == "warning" || logLevel == "2") {
      ul = LogLevel::WARN;
    } else if (logLevel == "info" || logLevel == "3") {
      ul = LogLevel::INFO;
    } else if (logLevel == "debug" || logLevel == "4") {
      ul = LogLevel::DEBUG;
    } else if (logLevel == "trace" || logLevel == "5") {
      ul = LogLevel::TRACE;
    } else {
      generateError(GeneralResponse::ResponseCode::BAD,
                    TRI_ERROR_HTTP_BAD_PARAMETER,
                    std::string("unknown '") + (found2 ? "level" : "upto") +
                        "' log level: '" + logLevel + "'");
      return status_t(HANDLER_DONE);
    }
  }

  // check the starting position
  uint64_t start = 0;

  bool found;
  std::string const& s = _request->value("start", found);

  if (found) {
    start = StringUtils::uint64(s);
  }

  // check the offset
  int64_t offset = 0;
  std::string const& o = _request->value("offset", found);

  if (found) {
    offset = StringUtils::int64(o);
  }

  // check the size
  uint64_t size = (uint64_t)-1;
  std::string const& si = _request->value("size", found);

  if (found) {
    size = StringUtils::uint64(si);
  }

  // check the sort direction
  bool sortAscending = true;
  std::string sortdir = StringUtils::tolower(_request->value("sort", found));

  if (found) {
    if (sortdir == "desc") {
      sortAscending = false;
    }
  }

  // check the search criteria
  bool search = false;
  std::string searchString =
      StringUtils::tolower(_request->value("search", search));

  // generate result
  std::vector<LogBuffer> entries = LogBuffer::entries(ul, start, useUpto);
  std::vector<LogBuffer> clean;

  if (search) {
    for (auto entry : entries) {
      std::string text = StringUtils::tolower(entry._message);

      if (text.find(searchString) == std::string::npos) {
        continue;
      }

      clean.emplace_back(entry);
    }
  } else {
    clean.swap(entries);
  }

  if (!sortAscending) {
    std::reverse(clean.begin(), clean.end());
  }

  VPackBuilder result;
  result.add(VPackValue(VPackValueType::Object));
  size_t length = clean.size();

  try {
    result.add("totalAmount", VPackValue(length));

    if (offset < 0) {
      offset = 0;
    } else if (offset >= static_cast<int64_t>(length)) {
      length = 0;
      offset = 0;
    } else if (offset > 0) {
      length -= static_cast<size_t>(offset);
    }

    // restrict to at most <size> elements
    if (length > size) {
      length = static_cast<size_t>(size);
    }

    // For now we build the arrays one ofter the other first id
    result.add("lid", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      result.add(VPackValue(buf._id));
    }

    result.close();

    // second level
    result.add("level", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      uint32_t l = 0;

      switch (buf._level) {
        case LogLevel::FATAL:
          l = 0;
          break;
        case LogLevel::ERR:
          l = 1;
          break;
        case LogLevel::WARN:
          l = 2;
          break;
        case LogLevel::DEFAULT:
        case LogLevel::INFO:
          l = 3;
          break;
        case LogLevel::DEBUG:
          l = 4;
          break;
        case LogLevel::TRACE:
          l = 5;
          break;
      }

      result.add(VPackValue(l));
    }

    result.close();

    // third timestamp
    result.add("timestamp", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      result.add(VPackValue(static_cast<size_t>(buf._timestamp)));
    }

    result.close();

    // fourth text
    result.add("text", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      result.add(VPackValue(buf._message));
    }

    result.close();

    result.close();  // Close the result object

    generateResult(GeneralResponse::ResponseCode::OK, result.slice());
  } catch (...) {
    // Not Enough memory to build everything up
    // Has been ignored thus far
    // So ignore again
  }

  return status_t(HANDLER_DONE);
}
<commit_msg>allow accessing /_admin/log in all databases<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Achim Brandt
////////////////////////////////////////////////////////////////////////////////

#include "RestAdminLogHandler.h"

#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>

#include "Basics/StringUtils.h"
#include "Logger/LogBuffer.h"
#include "Logger/Logger.h"
#include "Rest/HttpRequest.h"

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

RestAdminLogHandler::RestAdminLogHandler(HttpRequest* request)
    : RestBaseHandler(request) {}

bool RestAdminLogHandler::isDirect() const { return true; }

////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_get_admin_modules_flush
////////////////////////////////////////////////////////////////////////////////

HttpHandler::status_t RestAdminLogHandler::execute() {
  // check the maximal log level to report
  bool found1;
  std::string const& upto =
      StringUtils::tolower(_request->value("upto", found1));

  bool found2;
  std::string const& lvl =
      StringUtils::tolower(_request->value("level", found2));

  LogLevel ul = LogLevel::INFO;
  bool useUpto = true;
  std::string logLevel;

  // prefer level over upto
  if (found2) {
    logLevel = lvl;
    useUpto = false;
  } else if (found1) {
    logLevel = upto;
    useUpto = true;
  }

  if (found1 || found2) {
    if (logLevel == "fatal" || logLevel == "0") {
      ul = LogLevel::FATAL;
    } else if (logLevel == "error" || logLevel == "1") {
      ul = LogLevel::ERR;
    } else if (logLevel == "warning" || logLevel == "2") {
      ul = LogLevel::WARN;
    } else if (logLevel == "info" || logLevel == "3") {
      ul = LogLevel::INFO;
    } else if (logLevel == "debug" || logLevel == "4") {
      ul = LogLevel::DEBUG;
    } else if (logLevel == "trace" || logLevel == "5") {
      ul = LogLevel::TRACE;
    } else {
      generateError(GeneralResponse::ResponseCode::BAD,
                    TRI_ERROR_HTTP_BAD_PARAMETER,
                    std::string("unknown '") + (found2 ? "level" : "upto") +
                        "' log level: '" + logLevel + "'");
      return status_t(HANDLER_DONE);
    }
  }

  // check the starting position
  uint64_t start = 0;

  bool found;
  std::string const& s = _request->value("start", found);

  if (found) {
    start = StringUtils::uint64(s);
  }

  // check the offset
  int64_t offset = 0;
  std::string const& o = _request->value("offset", found);

  if (found) {
    offset = StringUtils::int64(o);
  }

  // check the size
  uint64_t size = (uint64_t)-1;
  std::string const& si = _request->value("size", found);

  if (found) {
    size = StringUtils::uint64(si);
  }

  // check the sort direction
  bool sortAscending = true;
  std::string sortdir = StringUtils::tolower(_request->value("sort", found));

  if (found) {
    if (sortdir == "desc") {
      sortAscending = false;
    }
  }

  // check the search criteria
  bool search = false;
  std::string searchString =
      StringUtils::tolower(_request->value("search", search));

  // generate result
  std::vector<LogBuffer> entries = LogBuffer::entries(ul, start, useUpto);
  std::vector<LogBuffer> clean;

  if (search) {
    for (auto entry : entries) {
      std::string text = StringUtils::tolower(entry._message);

      if (text.find(searchString) == std::string::npos) {
        continue;
      }

      clean.emplace_back(entry);
    }
  } else {
    clean.swap(entries);
  }

  if (!sortAscending) {
    std::reverse(clean.begin(), clean.end());
  }

  VPackBuilder result;
  result.add(VPackValue(VPackValueType::Object));
  size_t length = clean.size();

  try {
    result.add("totalAmount", VPackValue(length));

    if (offset < 0) {
      offset = 0;
    } else if (offset >= static_cast<int64_t>(length)) {
      length = 0;
      offset = 0;
    } else if (offset > 0) {
      length -= static_cast<size_t>(offset);
    }

    // restrict to at most <size> elements
    if (length > size) {
      length = static_cast<size_t>(size);
    }

    // For now we build the arrays one ofter the other first id
    result.add("lid", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      result.add(VPackValue(buf._id));
    }

    result.close();

    // second level
    result.add("level", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      uint32_t l = 0;

      switch (buf._level) {
        case LogLevel::FATAL:
          l = 0;
          break;
        case LogLevel::ERR:
          l = 1;
          break;
        case LogLevel::WARN:
          l = 2;
          break;
        case LogLevel::DEFAULT:
        case LogLevel::INFO:
          l = 3;
          break;
        case LogLevel::DEBUG:
          l = 4;
          break;
        case LogLevel::TRACE:
          l = 5;
          break;
      }

      result.add(VPackValue(l));
    }

    result.close();

    // third timestamp
    result.add("timestamp", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      result.add(VPackValue(static_cast<size_t>(buf._timestamp)));
    }

    result.close();

    // fourth text
    result.add("text", VPackValue(VPackValueType::Array));

    for (size_t i = 0; i < length; ++i) {
      auto& buf = clean.at(i + static_cast<size_t>(offset));
      result.add(VPackValue(buf._message));
    }

    result.close();

    result.close();  // Close the result object

    generateResult(GeneralResponse::ResponseCode::OK, result.slice());
  } catch (...) {
    // Not Enough memory to build everything up
    // Has been ignored thus far
    // So ignore again
  }

  return status_t(HANDLER_DONE);
}
<|endoftext|>


<commit_before><commit_msg>issue #2403<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  ll X, K;
  cin >> X >> K;
  ll g = 1;
  for (auto i = 0; i < K; ++i) {
    g *= 10;
  }
  ll amari = X % K;
  ll Y = X - amari + K;
  if (X == Y) {
    Y += K;
  }
  cout << Y << endl;
}
<commit_msg>submit B.cpp to 'B - オークション' (yahoo-procon2018-qual) [C++14 (GCC 5.4.1)]<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  ll X, K;
  cin >> X >> K;
  ll g = 1;
  for (auto i = 0; i < K; ++i) {
    g *= 10;
  }
  ll amari = X % g;
  ll Y = X - amari + g;
  if (X == Y) {
    Y += g;
  }
  cout << Y << endl;
}
<|endoftext|>


<commit_before>#include <string>

#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>

#include "client.h"

using namespace std;

namespace rpc {

void Future::wait() {
    Pthread_mutex_lock(&ready_m_);
    while (!ready_) {
        Pthread_cond_wait(&ready_cond_, &ready_m_);
    }
    Pthread_mutex_unlock(&ready_m_);
}

Client::Client(PollMgr* pollmgr, ThreadPool* thrpool /* =? */)
        : thrpool_(thrpool), pollmgr_(pollmgr), sock_(-1), status_(NEW), bmark_(NULL) {
    Pthread_mutex_init(&pending_fu_m_, NULL);
    Pthread_mutex_init(&out_m_, NULL);
}

Client::~Client() {
    invalidate_pending_futures();

    Pthread_mutex_destroy(&pending_fu_m_);
    Pthread_mutex_destroy(&out_m_);

    //Log::debug("rpc::Client: destroyed");
}

void Client::invalidate_pending_futures() {
    list<Future*> futures;
    Pthread_mutex_lock(&pending_fu_m_);
    for (map<i64, Future*>::iterator it = pending_fu_.begin(); it != pending_fu_.end(); ++it) {
        futures.push_back(it->second);
    }
    Pthread_mutex_unlock(&pending_fu_m_);

    for (list<Future*>::iterator it = futures.begin(); it != futures.end(); ++it) {
        Pthread_mutex_lock(&pending_fu_m_);
        map<i64, Future*>::iterator find_it = pending_fu_.find((*it)->xid_);
        Future* fu = NULL;
        if (find_it != pending_fu_.end()) {
            fu = find_it->second;
            pending_fu_.erase(find_it);
        }
        Pthread_mutex_unlock(&pending_fu_m_);

        if (fu != NULL) {
            fu->error_code_ = ENOTCONN;

            Pthread_mutex_lock(&fu->ready_m_);
            fu->ready_ = true;
            Pthread_cond_signal(&fu->ready_cond_);
            Pthread_mutex_unlock(&fu->ready_m_);

            RUNNABLE_CLASS1(R, Future*, fu, {
                if (fu->attr_.callback != NULL) {
                    fu->attr_.callback->run(fu);

                    // automatically cleanup the callback
                    delete fu->attr_.callback;
                    fu->attr_.callback = NULL;
                }

                // since we removed it from pending_fu_
                fu->release();
            });

            if (thrpool_ != NULL) {
                thrpool_->run_async(new R(fu));
            } else {
                R r(fu);
                r.run();
            }
        }
    }

}

void Client::close() {
    if (status_ == CONNECTED) {
        pollmgr_->remove(this);
        ::close(sock_);
        status_ = CLOSED;

        invalidate_pending_futures();
    }
    status_ = CLOSED;
}

int Client::connect(const char* addr) {
    string addr_str(addr);
    size_t idx = addr_str.find(":");
    if (idx == string::npos) {
        Log::error("rpc::Client: bad connect address: %s", addr);
        errno = EINVAL;
        return -1;
    }
    string host = addr_str.substr(0, idx);
    string port = addr_str.substr(idx + 1);

    struct addrinfo hints, *result, *rp;
    memset(&hints, 0, sizeof(struct addrinfo));

    hints.ai_family = AF_INET; // ipv4
    hints.ai_socktype = SOCK_STREAM; // tcp

    int r = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
    if (r != 0) {
        Log::error("rpc::Client: getaddrinfo(): %s", gai_strerror(r));
        return -1;
    }

    for (rp = result; rp != NULL; rp = rp->ai_next) {
        sock_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sock_ == -1) {
            continue;
        }

        const int yes = 1;
        verify(setsockopt(sock_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == 0);
        verify(setsockopt(sock_, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == 0);

        if (::connect(sock_, rp->ai_addr, rp->ai_addrlen) == 0) {
            break;
        }
        ::close(sock_);
        sock_ = -1;
    }
    freeaddrinfo(result);

    if (rp == NULL) {
        // failed to connect
        Log::error("rpc::Client: connect(): %s", strerror(errno));
        return -1;
    }

    verify(set_nonblocking(sock_, true) == 0);
    Log::info("rpc::Client: connected to %s", addr);

    status_ = CONNECTED;
    pollmgr_->add(this);

    return 0;
}

void Client::handle_error() {
    close();
}

void Client::handle_write() {
    if (status_ != CONNECTED) {
        return;
    }

    Pthread_mutex_lock(&out_m_);
    out_.write_to_fd(sock_);
    if (out_.empty()) {
        pollmgr_->update_mode(this, Pollable::READ);
    }
    Pthread_mutex_unlock(&out_m_);
}

void Client::handle_read() {
    if (status_ != CONNECTED) {
        return;
    }

    int bytes_read = in_.read_from_fd(sock_);
    if (bytes_read == 0) {
        return;
    }

    for (;;) {
        i32 packet_size;
        int n_peek = in_.peek(&packet_size, sizeof(i32));
        if (n_peek == sizeof(i32) && in_.content_size_gt(packet_size + sizeof(i32) - 1)) {
            // consume the packet size
            verify(in_.read(&packet_size, sizeof(i32)) == sizeof(i32));

            i64 reply_xid;
            i32 error_code;

            in_ >> reply_xid >> error_code;

            Pthread_mutex_lock(&pending_fu_m_);
            map<i64, Future*>::iterator it = pending_fu_.find(reply_xid);
            verify(it != pending_fu_.end());

            Future* fu = it->second;
            verify(fu->xid_ == reply_xid);
            pending_fu_.erase(it);
            Pthread_mutex_unlock(&pending_fu_m_);

            fu->error_code_ = error_code;
            fu->reply_.read_from_marshal(in_, packet_size - sizeof(reply_xid) - sizeof(error_code));

            Pthread_mutex_lock(&fu->ready_m_);
            fu->ready_ = true;
            Pthread_cond_signal(&fu->ready_cond_);
            Pthread_mutex_unlock(&fu->ready_m_);

            if (fu->attr_.callback != NULL) {
                fu->attr_.callback->run(fu);

                // automatically cleanup the callback
                delete fu->attr_.callback;
                fu->attr_.callback = NULL;
            }

            // since we removed it from pending_fu_
            fu->release();

        } else {
            // packet incomplete or no more packets to process
            break;
        }
    }
}

int Client::poll_mode() {
    int mode = Pollable::READ;
    Pthread_mutex_lock(&out_m_);
    if (!out_.empty()) {
        mode |= Pollable::WRITE;
    }
    Pthread_mutex_unlock(&out_m_);
    return mode;
}

Future* Client::begin_request(i32 rpc_id, const FutureAttr& attr /* =... */) {
    Pthread_mutex_lock(&out_m_);

    if (status_ != CONNECTED) {
        return NULL;
    }

    Future* fu = new Future(xid_counter_.next(), attr);
    Pthread_mutex_lock(&pending_fu_m_);
    pending_fu_[fu->xid_] = fu;
    pending_fu_.size();
    Pthread_mutex_unlock(&pending_fu_m_);

    // check if the client gets closed in the meantime
    if (status_ != CONNECTED) {
        Pthread_mutex_lock(&pending_fu_m_);
        map<i64, Future*>::iterator it = pending_fu_.find(fu->xid_);
        if (it != pending_fu_.end()) {
            it->second->release();
            pending_fu_.erase(it);
        }
        Pthread_mutex_unlock(&pending_fu_m_);

        return NULL;
    }

    bmark_ = out_.set_bookmark(sizeof(i32)); // will fill packet size later

    *this << fu->xid_;
    *this << rpc_id;

    // one ref is already in pending_fu_
    return (Future *) fu->ref_copy();
}

void Client::end_request() {
    // set reply size in packet
    if (bmark_ != NULL) {
        i32 request_size = out_.get_write_counter_and_reset();
        out_.write_bookmark(bmark_, &request_size);
        delete bmark_;
        bmark_ = NULL;
    }

    if (!out_.empty()) {
        pollmgr_->update_mode(this, Pollable::READ | Pollable::WRITE);
    }

    Pthread_mutex_unlock(&out_m_);
}

ClientPool::ClientPool(PollMgr* pollmgr) {
    Pthread_mutex_init(&m_, NULL);

    if (pollmgr == NULL) {
        pollmgr_ = new PollMgr(1);
    } else {
        pollmgr_ = (PollMgr *) pollmgr->ref_copy();
    }
}

ClientPool::~ClientPool() {
    for (map<string, Client*>::iterator it = cache_.begin(); it != cache_.end(); ++it) {
        it->second->close_and_release();
    }

    pollmgr_->release();

    Pthread_mutex_destroy(&m_);
}

Client* ClientPool::get_client(const string& addr) {
    Client* cl = NULL;
    Pthread_mutex_lock(&m_);
    map<string, Client*>::iterator it = cache_.find(addr);
    if (it != cache_.end()) {
        cl = it->second;
    } else {
        cl = new Client(this->pollmgr_, &this->thrpool_);
        if (cl->connect(addr.c_str()) != 0) {
            // connect failure
            cl->close_and_release();
            cl = NULL;
        } else {
            // connect success
            cache_[addr] = cl;
        }
    }
    Pthread_mutex_unlock(&m_);
    return cl;
}

}
<commit_msg>execute callback in thrpool<commit_after>#include <string>

#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>

#include "client.h"

using namespace std;

namespace rpc {

void Future::wait() {
    Pthread_mutex_lock(&ready_m_);
    while (!ready_) {
        Pthread_cond_wait(&ready_cond_, &ready_m_);
    }
    Pthread_mutex_unlock(&ready_m_);
}

Client::Client(PollMgr* pollmgr, ThreadPool* thrpool /* =? */)
        : thrpool_(thrpool), pollmgr_(pollmgr), sock_(-1), status_(NEW), bmark_(NULL) {
    Pthread_mutex_init(&pending_fu_m_, NULL);
    Pthread_mutex_init(&out_m_, NULL);
}

Client::~Client() {
    invalidate_pending_futures();

    Pthread_mutex_destroy(&pending_fu_m_);
    Pthread_mutex_destroy(&out_m_);

    //Log::debug("rpc::Client: destroyed");
}

void Client::invalidate_pending_futures() {
    list<Future*> futures;
    Pthread_mutex_lock(&pending_fu_m_);
    for (map<i64, Future*>::iterator it = pending_fu_.begin(); it != pending_fu_.end(); ++it) {
        futures.push_back(it->second);
    }
    Pthread_mutex_unlock(&pending_fu_m_);

    for (list<Future*>::iterator it = futures.begin(); it != futures.end(); ++it) {
        Pthread_mutex_lock(&pending_fu_m_);
        map<i64, Future*>::iterator find_it = pending_fu_.find((*it)->xid_);
        Future* fu = NULL;
        if (find_it != pending_fu_.end()) {
            fu = find_it->second;
            pending_fu_.erase(find_it);
        }
        Pthread_mutex_unlock(&pending_fu_m_);

        if (fu != NULL) {
            fu->error_code_ = ENOTCONN;

            Pthread_mutex_lock(&fu->ready_m_);
            fu->ready_ = true;
            Pthread_cond_signal(&fu->ready_cond_);
            Pthread_mutex_unlock(&fu->ready_m_);

            RUNNABLE_CLASS1(R, Future*, fu, {
                if (fu->attr_.callback != NULL) {
                    fu->attr_.callback->run(fu);

                    // automatically cleanup the callback
                    delete fu->attr_.callback;
                    fu->attr_.callback = NULL;
                }

                // since we removed it from pending_fu_
                fu->release();
            });

            if (thrpool_ != NULL) {
                thrpool_->run_async(new R(fu));
            } else {
                R r(fu);
                r.run();
            }
        }
    }

}

void Client::close() {
    if (status_ == CONNECTED) {
        pollmgr_->remove(this);
        ::close(sock_);
        status_ = CLOSED;

        invalidate_pending_futures();
    }
    status_ = CLOSED;
}

int Client::connect(const char* addr) {
    string addr_str(addr);
    size_t idx = addr_str.find(":");
    if (idx == string::npos) {
        Log::error("rpc::Client: bad connect address: %s", addr);
        errno = EINVAL;
        return -1;
    }
    string host = addr_str.substr(0, idx);
    string port = addr_str.substr(idx + 1);

    struct addrinfo hints, *result, *rp;
    memset(&hints, 0, sizeof(struct addrinfo));

    hints.ai_family = AF_INET; // ipv4
    hints.ai_socktype = SOCK_STREAM; // tcp

    int r = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
    if (r != 0) {
        Log::error("rpc::Client: getaddrinfo(): %s", gai_strerror(r));
        return -1;
    }

    for (rp = result; rp != NULL; rp = rp->ai_next) {
        sock_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sock_ == -1) {
            continue;
        }

        const int yes = 1;
        verify(setsockopt(sock_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == 0);
        verify(setsockopt(sock_, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == 0);

        if (::connect(sock_, rp->ai_addr, rp->ai_addrlen) == 0) {
            break;
        }
        ::close(sock_);
        sock_ = -1;
    }
    freeaddrinfo(result);

    if (rp == NULL) {
        // failed to connect
        Log::error("rpc::Client: connect(): %s", strerror(errno));
        return -1;
    }

    verify(set_nonblocking(sock_, true) == 0);
    Log::info("rpc::Client: connected to %s", addr);

    status_ = CONNECTED;
    pollmgr_->add(this);

    return 0;
}

void Client::handle_error() {
    close();
}

void Client::handle_write() {
    if (status_ != CONNECTED) {
        return;
    }

    Pthread_mutex_lock(&out_m_);
    out_.write_to_fd(sock_);
    if (out_.empty()) {
        pollmgr_->update_mode(this, Pollable::READ);
    }
    Pthread_mutex_unlock(&out_m_);
}

void Client::handle_read() {
    if (status_ != CONNECTED) {
        return;
    }

    int bytes_read = in_.read_from_fd(sock_);
    if (bytes_read == 0) {
        return;
    }

    for (;;) {
        i32 packet_size;
        int n_peek = in_.peek(&packet_size, sizeof(i32));
        if (n_peek == sizeof(i32) && in_.content_size_gt(packet_size + sizeof(i32) - 1)) {
            // consume the packet size
            verify(in_.read(&packet_size, sizeof(i32)) == sizeof(i32));

            i64 reply_xid;
            i32 error_code;

            in_ >> reply_xid >> error_code;

            Pthread_mutex_lock(&pending_fu_m_);
            map<i64, Future*>::iterator it = pending_fu_.find(reply_xid);
            verify(it != pending_fu_.end());

            Future* fu = it->second;
            verify(fu->xid_ == reply_xid);
            pending_fu_.erase(it);
            Pthread_mutex_unlock(&pending_fu_m_);

            fu->error_code_ = error_code;
            fu->reply_.read_from_marshal(in_, packet_size - sizeof(reply_xid) - sizeof(error_code));

            Pthread_mutex_lock(&fu->ready_m_);
            fu->ready_ = true;
            Pthread_cond_signal(&fu->ready_cond_);
            Pthread_mutex_unlock(&fu->ready_m_);

            RUNNABLE_CLASS1(R, Future*, fu, {
                if (fu->attr_.callback != NULL) {
                    fu->attr_.callback->run(fu);

                    // automatically cleanup the callback
                    delete fu->attr_.callback;
                    fu->attr_.callback = NULL;
                }

                // since we removed it from pending_fu_
                fu->release();
            });

            if (thrpool_ != NULL) {
                thrpool_->run_async(new R(fu));
            } else {
                R r(fu);
                r.run();
            }

        } else {
            // packet incomplete or no more packets to process
            break;
        }
    }
}

int Client::poll_mode() {
    int mode = Pollable::READ;
    Pthread_mutex_lock(&out_m_);
    if (!out_.empty()) {
        mode |= Pollable::WRITE;
    }
    Pthread_mutex_unlock(&out_m_);
    return mode;
}

Future* Client::begin_request(i32 rpc_id, const FutureAttr& attr /* =... */) {
    Pthread_mutex_lock(&out_m_);

    if (status_ != CONNECTED) {
        return NULL;
    }

    Future* fu = new Future(xid_counter_.next(), attr);
    Pthread_mutex_lock(&pending_fu_m_);
    pending_fu_[fu->xid_] = fu;
    pending_fu_.size();
    Pthread_mutex_unlock(&pending_fu_m_);

    // check if the client gets closed in the meantime
    if (status_ != CONNECTED) {
        Pthread_mutex_lock(&pending_fu_m_);
        map<i64, Future*>::iterator it = pending_fu_.find(fu->xid_);
        if (it != pending_fu_.end()) {
            it->second->release();
            pending_fu_.erase(it);
        }
        Pthread_mutex_unlock(&pending_fu_m_);

        return NULL;
    }

    bmark_ = out_.set_bookmark(sizeof(i32)); // will fill packet size later

    *this << fu->xid_;
    *this << rpc_id;

    // one ref is already in pending_fu_
    return (Future *) fu->ref_copy();
}

void Client::end_request() {
    // set reply size in packet
    if (bmark_ != NULL) {
        i32 request_size = out_.get_write_counter_and_reset();
        out_.write_bookmark(bmark_, &request_size);
        delete bmark_;
        bmark_ = NULL;
    }

    if (!out_.empty()) {
        pollmgr_->update_mode(this, Pollable::READ | Pollable::WRITE);
    }

    Pthread_mutex_unlock(&out_m_);
}

ClientPool::ClientPool(PollMgr* pollmgr) {
    Pthread_mutex_init(&m_, NULL);

    if (pollmgr == NULL) {
        pollmgr_ = new PollMgr(1);
    } else {
        pollmgr_ = (PollMgr *) pollmgr->ref_copy();
    }
}

ClientPool::~ClientPool() {
    for (map<string, Client*>::iterator it = cache_.begin(); it != cache_.end(); ++it) {
        it->second->close_and_release();
    }

    pollmgr_->release();

    Pthread_mutex_destroy(&m_);
}

Client* ClientPool::get_client(const string& addr) {
    Client* cl = NULL;
    Pthread_mutex_lock(&m_);
    map<string, Client*>::iterator it = cache_.find(addr);
    if (it != cache_.end()) {
        cl = it->second;
    } else {
        cl = new Client(this->pollmgr_, &this->thrpool_);
        if (cl->connect(addr.c_str()) != 0) {
            // connect failure
            cl->close_and_release();
            cl = NULL;
        } else {
            // connect success
            cache_[addr] = cl;
        }
    }
    Pthread_mutex_unlock(&m_);
    return cl;
}

}
<|endoftext|>


<commit_before>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "PDB.h"
#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/BinaryByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>

using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;
using namespace llvm::support::endian;

using llvm::object::coff_section;

static ExitOnError ExitOnErr;

// Returns a list of all SectionChunks.
static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
  std::vector<coff_section> V;
  for (Chunk *C : Symtab->getChunks())
    if (auto *SC = dyn_cast<SectionChunk>(C))
      V.push_back(*SC->Header);
  return V;
}

static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
                                StringRef Name) {
  for (SectionChunk *C : Sections)
    if (C->getSectionName() == Name)
      return C;
  return nullptr;
}

static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
  SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
  if (!Sec)
    return {};

  // First 4 bytes are section magic.
  ArrayRef<uint8_t> Data = Sec->getContents();
  if (Data.size() < 4)
    fatal(SecName + " too short");
  if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
    fatal(SecName + " has an invalid magic");
  return Data.slice(4);
}

// Merge .debug$T sections and returns it.
static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  // Visit all .debug$T sections to add them to Builder.
  codeview::TypeTableBuilder Builder(BAlloc);
  for (ObjectFile *File : Symtab->ObjectFiles) {
    ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
    if (Data.empty())
      continue;

    BinaryByteStream Stream(Data, llvm::support::little);
    codeview::CVTypeArray Types;
    BinaryStreamReader Reader(Stream);
    // Follow type servers.  If the same type server is encountered more than
    // once for this instance of `PDBTypeServerHandler` (for example if many
    // object files reference the same TypeServer), the types from the
    // TypeServer will only be visited once.
    pdb::PDBTypeServerHandler Handler;
    Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
    if (auto EC = Reader.readArray(Types, Reader.getLength()))
      fatal(EC, "Reader::readArray failed");
    if (auto Err = codeview::mergeTypeStreams(Builder, &Handler, Types))
      fatal(Err, "codeview::mergeTypeStreams failed");
  }

  // Construct section contents.
  std::vector<uint8_t> V;
  Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
    V.insert(V.end(), Rec.begin(), Rec.end());
  });
  return V;
}

static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugT");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
  if (Data.empty())
    return;

  TypeDatabase TDB;
  TypeDumpVisitor TDV(TDB, &W, false);
  // Use a default implementation that does not follow type servers and instead
  // just dumps the contents of the TypeServer2 record.
  CVTypeDumper TypeDumper(TDB);
  if (auto EC = TypeDumper.dump(Data, TDV))
    fatal(EC, "CVTypeDumper::dump failed");
}

static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugS");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
  if (Data.empty())
    return;

  BinaryByteStream Stream(Data, llvm::support::little);
  CVSymbolArray Symbols;
  BinaryStreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
    fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");

  TypeDatabase TDB;
  CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
  if (auto EC = SymbolDumper.dump(Symbols))
    fatal(EC, "CVSymbolDumper::dump failed");
}

// Dump CodeView debug info. This is for debugging.
static void dumpCodeView(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  for (ObjectFile *File : Symtab->ObjectFiles) {
    dumpDebugT(W, File);
    dumpDebugS(W, File);
  }
}

static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
                        ArrayRef<uint8_t> Data) {
  BinaryByteStream Stream(Data, llvm::support::little);
  codeview::CVTypeArray Records;
  BinaryStreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Records, Reader.getLength()))
    fatal(EC, "Reader.readArray failed");
  for (const codeview::CVType &Rec : Records)
    TpiBuilder.addTypeRecord(Rec);
}

// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                     ArrayRef<uint8_t> SectionTable,
                     const llvm::codeview::DebugInfo *DI) {
  if (Config->DumpPdb)
    dumpCodeView(Symtab);

  BumpPtrAllocator Alloc;
  pdb::PDBFileBuilder Builder(Alloc);
  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize

  // Create streams in MSF for predefined streams, namely
  // PDB, TPI, DBI and IPI.
  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
    ExitOnErr(Builder.getMsfBuilder().addStream(0));

  // Add an Info stream.
  auto &InfoBuilder = Builder.getInfoBuilder();
  InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);

  pdb::PDB_UniqueId uuid{};
  if (DI)
    memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
  InfoBuilder.setGuid(uuid);
  // Should be the current time, but set 0 for reproducibilty.
  InfoBuilder.setSignature(0);
  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);

  // Add an empty DPI stream.
  auto &DbiBuilder = Builder.getDbiBuilder();
  DbiBuilder.setVersionHeader(pdb::PdbDbiV110);

  // Add an empty TPI stream.
  auto &TpiBuilder = Builder.getTpiBuilder();
  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
  std::vector<uint8_t> TpiData;
  if (Config->DebugPdb) {
    TpiData = mergeDebugT(Symtab);
    addTypeInfo(TpiBuilder, TpiData);
  }

  // Add an empty IPI stream.
  auto &IpiBuilder = Builder.getIpiBuilder();
  IpiBuilder.setVersionHeader(pdb::PdbTpiV80);

  // Add Section Contributions.
  std::vector<pdb::SectionContrib> Contribs =
      pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
  DbiBuilder.setSectionContribs(Contribs);

  // Add Section Map stream.
  ArrayRef<object::coff_section> Sections = {
      (const object::coff_section *)SectionTable.data(),
      SectionTable.size() / sizeof(object::coff_section)};
  std::vector<pdb::SecMapEntry> SectionMap =
      pdb::DbiStreamBuilder::createSectionMap(Sections);
  DbiBuilder.setSectionMap(SectionMap);

  ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));

  // Add COFF section header stream.
  ExitOnErr(
      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));

  // Write to a file.
  ExitOnErr(Builder.commit(Path));
}
<commit_msg>Revert r296215, "[PDB] General improvements to Stream library." and followings.<commit_after>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "PDB.h"
#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/BinaryByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>

using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;
using namespace llvm::support::endian;

using llvm::object::coff_section;

static ExitOnError ExitOnErr;

// Returns a list of all SectionChunks.
static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
  std::vector<coff_section> V;
  for (Chunk *C : Symtab->getChunks())
    if (auto *SC = dyn_cast<SectionChunk>(C))
      V.push_back(*SC->Header);
  return V;
}

static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
                                StringRef Name) {
  for (SectionChunk *C : Sections)
    if (C->getSectionName() == Name)
      return C;
  return nullptr;
}

static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
  SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
  if (!Sec)
    return {};

  // First 4 bytes are section magic.
  ArrayRef<uint8_t> Data = Sec->getContents();
  if (Data.size() < 4)
    fatal(SecName + " too short");
  if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
    fatal(SecName + " has an invalid magic");
  return Data.slice(4);
}

// Merge .debug$T sections and returns it.
static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  // Visit all .debug$T sections to add them to Builder.
  codeview::TypeTableBuilder Builder(BAlloc);
  for (ObjectFile *File : Symtab->ObjectFiles) {
    ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
    if (Data.empty())
      continue;

    msf::ByteStream Stream(Data);
    codeview::CVTypeArray Types;
    msf::StreamReader Reader(Stream);
    // Follow type servers.  If the same type server is encountered more than
    // once for this instance of `PDBTypeServerHandler` (for example if many
    // object files reference the same TypeServer), the types from the
    // TypeServer will only be visited once.
    pdb::PDBTypeServerHandler Handler;
    Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
    if (auto EC = Reader.readArray(Types, Reader.getLength()))
      fatal(EC, "Reader::readArray failed");
    if (auto Err = codeview::mergeTypeStreams(Builder, &Handler, Types))
      fatal(Err, "codeview::mergeTypeStreams failed");
  }

  // Construct section contents.
  std::vector<uint8_t> V;
  Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
    V.insert(V.end(), Rec.begin(), Rec.end());
  });
  return V;
}

static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugT");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
  if (Data.empty())
    return;

  TypeDatabase TDB;
  TypeDumpVisitor TDV(TDB, &W, false);
  // Use a default implementation that does not follow type servers and instead
  // just dumps the contents of the TypeServer2 record.
  CVTypeDumper TypeDumper(TDB);
  if (auto EC = TypeDumper.dump(Data, TDV))
    fatal(EC, "CVTypeDumper::dump failed");
}

static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugS");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
  if (Data.empty())
    return;

  msf::ByteStream Stream(Data);
  CVSymbolArray Symbols;
  msf::StreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
    fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");

  TypeDatabase TDB;
  CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
  if (auto EC = SymbolDumper.dump(Symbols))
    fatal(EC, "CVSymbolDumper::dump failed");
}

// Dump CodeView debug info. This is for debugging.
static void dumpCodeView(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  for (ObjectFile *File : Symtab->ObjectFiles) {
    dumpDebugT(W, File);
    dumpDebugS(W, File);
  }
}

static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
                        ArrayRef<uint8_t> Data) {
  msf::ByteStream Stream(Data);
  codeview::CVTypeArray Records;
  msf::StreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Records, Reader.getLength()))
    fatal(EC, "Reader.readArray failed");
  for (const codeview::CVType &Rec : Records)
    TpiBuilder.addTypeRecord(Rec);
}

// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                     ArrayRef<uint8_t> SectionTable,
                     const llvm::codeview::DebugInfo *DI) {
  if (Config->DumpPdb)
    dumpCodeView(Symtab);

  BumpPtrAllocator Alloc;
  pdb::PDBFileBuilder Builder(Alloc);
  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize

  // Create streams in MSF for predefined streams, namely
  // PDB, TPI, DBI and IPI.
  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
    ExitOnErr(Builder.getMsfBuilder().addStream(0));

  // Add an Info stream.
  auto &InfoBuilder = Builder.getInfoBuilder();
  InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);

  pdb::PDB_UniqueId uuid{};
  if (DI)
    memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
  InfoBuilder.setGuid(uuid);
  // Should be the current time, but set 0 for reproducibilty.
  InfoBuilder.setSignature(0);
  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);

  // Add an empty DPI stream.
  auto &DbiBuilder = Builder.getDbiBuilder();
  DbiBuilder.setVersionHeader(pdb::PdbDbiV110);

  // Add an empty TPI stream.
  auto &TpiBuilder = Builder.getTpiBuilder();
  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
  std::vector<uint8_t> TpiData;
  if (Config->DebugPdb) {
    TpiData = mergeDebugT(Symtab);
    addTypeInfo(TpiBuilder, TpiData);
  }

  // Add an empty IPI stream.
  auto &IpiBuilder = Builder.getIpiBuilder();
  IpiBuilder.setVersionHeader(pdb::PdbTpiV80);

  // Add Section Contributions.
  std::vector<pdb::SectionContrib> Contribs =
      pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
  DbiBuilder.setSectionContribs(Contribs);

  // Add Section Map stream.
  ArrayRef<object::coff_section> Sections = {
      (const object::coff_section *)SectionTable.data(),
      SectionTable.size() / sizeof(object::coff_section)};
  std::vector<pdb::SecMapEntry> SectionMap =
      pdb::DbiStreamBuilder::createSectionMap(Sections);
  DbiBuilder.setSectionMap(SectionMap);

  ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));

  // Add COFF section header stream.
  ExitOnErr(
      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));

  // Write to a file.
  ExitOnErr(Builder.commit(Path));
}
<|endoftext|>