Česky
Kamil Dudka

GED 2006 (C++)

File detail

Name:Downloadpluginsupport.cc [Download]
Location: ged2006 > src
Size:7.1 KB
Last modification:2007-08-29 02:16

Source code

/*
 * File: pluginsuppport.cc - Maintain plugins
 * Project: GED - bitmap editor (ICP)
 * Author: Kamil Dudka, xdudka00
 * Team: xdudka00, xfilak01, xhefka00, xhradi08
 * Created: 2006-04-06
 */
 
 
#include <iostream>
#include <sstream>
#include <string>
#include <map>
 
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
 
#include "global.h"
#include "pluginsupport.h"
 
using std::string;
using std::map;
 
using GlobalH::min;
using GlobalH::max;
 
typedef map<string, string> TPluginNameMap;
 
/*
 * Initialize singleton PluginList
 */
PluginList *PluginList::_instance = 0;
 
/*
 * Global point to singleton PluginList
 */
PluginList *PluginList::ptr ()
{
	if (0== _instance)
		_instance = new PluginList;
 
	return _instance;
}
 
/*
 * This function should be called on program exit
 */
void PluginList::destroy ()
{
	delete _instance;
}
 
/*
 * PluginList destructor
 */
PluginList::~PluginList ()
{
	_instance = 0;
}
 
/*
 * return true if file "szFileName" is executable for "procUid" or "procGid"
 */
static inline bool isExec (const char *szFileName, uid_t procUid, gid_t procGid) {
	struct stat fileInfo;
	if (0!= stat (szFileName, &fileInfo))
		// could not read fileInfo
		return false;
 
	if (!(fileInfo.st_mode & S_IFREG) || !(fileInfo.st_mode & S_IFLNK))
		// not a file
		return false;
 
	return
		(fileInfo.st_mode & S_IXOTH) ||
		((fileInfo.st_mode & S_IXUSR) && fileInfo.st_uid == procUid) ||
		((fileInfo.st_mode & S_IXGRP) && fileInfo.st_gid == procGid);
}
 
/*
 * Lookup for plugins in directory "szDirectory"
 */
void PluginList::pluginDirLookup (const char *szDirectory)
{
#ifndef NDEBUG
	std::cerr << "Scanning directory \'" << szDirectory << "\' for plugins:\n";
#endif
	DIR *pDir = opendir (szDirectory);
	if (NULL== pDir)
		throw ErrPluginDir ();
 
	uid_t myUid = getuid ();
	gid_t myGid = getgid ();
 
	// Scan opened directory for executable files
	for (struct dirent *currDir; NULL!= (currDir= readdir (pDir)); ) {
		string fileName = string (szDirectory) + "/" + currDir->d_name;
 
		if (!isExec (fileName.c_str(), myUid, myGid))
			// File not executable
			continue;
 
		// Try to add plugin
		addPluginFile (fileName);
	}
 
	closedir (pDir);
#ifndef NDEBUG
	std::cerr << "Directory scan complete..\n";
#endif
}
 
/*
 * Add file "fileName" as plugin (if recornized)
 */
void PluginList::addPluginFile (std::string &fileName)
{
	// Plugin name limit
	const size_t pluginNameLength = 256;
 
	// Run plugin with "--name" option
	FILE *pluginPipe = popen ((fileName + " --name").c_str(), "r");
 
	// Read identification
	char szPluginName [pluginNameLength];
	const size_t cbRead = fread (szPluginName, sizeof(char), pluginNameLength, pluginPipe);
	szPluginName [ min<unsigned> (pluginNameLength-1, max<int> (0, int(cbRead)-1)) ] = '\0';
 
	// Wait
	if (0!= pclose (pluginPipe))
		return;
 
	// Add plugin to plugin map
	_pluginNameMap [string (szPluginName)] = fileName;
#ifndef NDEBUG
	std::cerr << "     \'" << szPluginName << "\'\n";
#endif
}
 
/*
 * Call plugin
 * fb: FrameBuffer to share
 * pluginName: name (id) of called plugin
 * args: plugin arguments
 */
void PluginList::callByName (FrameBuffer &fb, std::string pluginName, std::string args)
{
	// Lookup for plugin fileName
	TPluginNameMap::iterator i= _pluginNameMap.find (pluginName);
	if (i == _pluginNameMap.end ())
		throw ErrPluginNotFound ();
 
	invokePlugin (fb, (*i).second, args);
}
 
/*
 * Call plugin
 * fb: FrameBuffer to share
 * cmd: complete cmd-line string to call plugin
 */
void PluginList::invokePlugin (FrameBuffer &fb, std::string &fileName, std::string &args)
{
	int shmID = SharedObject::create (fb);
 
	// Build cmd using stream
	std::ostringstream cmdStream;
	cmdStream << fileName << " " << shmID << " " << args;
 
	// Save stream to string
	string cmd = cmdStream.str();
#ifndef NDEBUG
	std::cerr << "Plugin call: " << cmd << "\n";
#endif
 
	// Plugin call
	if (int iErrCode = system (cmd.c_str()) ) {
		SharedObject::destroy (shmID);
		throw ErrPluginEC (iErrCode);
	}
 
	// Commit changes to fb
	fb = SharedFrameBuffer (shmID);
	SharedObject::destroy (shmID);
}
 
/*
 * Create shared object from fb
 * return: id of shared object
 */
int SharedObject::create (FrameBuffer &fb)
{
#ifndef NDEBUG
	std::cerr << "Creating shared object..\n";
#endif
	// Allocate shm for SharedObject
	int soID = shmget (IPC_PRIVATE, sizeof(SharedObject), IPC_CREAT | 0600 );
	SharedObject *pSO = attach (soID);
 
	pSO->_fb._size = fb._size;
	pSO->_fb._select = fb._select;
	pSO->_fb._pBuff = 0;
 
	// Allocate shm for bitmap
	pSO->bitmapAlloc (fb._size);
 
	// Copy bitmap
	Pixel *bitmap = pSO->bitmapAttach();
	for (int i=0; i<fb._size.nPixels(); i++)
		bitmap[i] = fb._pBuff[i];
	shmdt (bitmap);
 
	detach (pSO);
	return soID;
}
 
/*
 * Destroy shared object
 * shmID: id returned by create()
 */
void SharedObject::destroy (int shmID)
{
#ifndef NDEBUG
	std::cerr << "Deleting shared object..\n";
#endif
	SharedObject *pSO = attach (shmID);
	pSO->bitmapFree ();
	detach (pSO);
 
	shmctl (shmID, IPC_RMID, NULL);
}
 
/*
 * Attach process to shared object
 * shmID: id of shared object
 * return: address of shared object
 */
SharedObject *SharedObject::attach (int shmID)
{
	return static_cast<SharedObject *>(shmat (shmID, NULL, 0));
}
 
/*
 * Detach process from shared object
 * addr: address of shared object returned by attach()
 */
void SharedObject::detach (SharedObject *addr)
{
	shmdt (addr);
}
 
/*
 * Free shm allocated by bitmapAlloc()
 */
void SharedObject::bitmapFree ()
{
	shmctl (_shmBitmap, IPC_RMID, NULL);
}
 
/*
 * Allocate shared bitmap of size "size"
 */
void SharedObject::bitmapAlloc (BoxSize &size)
{
	_shmBitmap = shmget (IPC_PRIVATE, size.nPixels() * sizeof(Pixel), IPC_CREAT | 0600 );
}
/*
 * Attach process to bitmap
 * return: address of attached bitmap
 */
Pixel *SharedObject::bitmapAttach ()
{
	return static_cast<Pixel *>(shmat (_shmBitmap, NULL, 0));
}
 
/*
 * Detach process from bitmap
 * addr: address of bitmap object returned by bitmapAttach()
 */
void SharedObject::detach (Pixel *addr)
{
	shmdt (addr);
}
 
/*
 * Create frame buffer from shared object
 * shmID: id of shared object
 */
SharedFrameBuffer::SharedFrameBuffer (int shmID)
{
#ifndef NDEBUG
	std::cerr<<"Importing data from shared object..\n";
#endif
	SharedObject *src = SharedObject::attach (shmID);
 
	// set fb properties
	this->size (src->pFB()->_size);
	this->select (src->pFB()->_select);
 
	// copy bitmap
	Pixel *bitmap = src->bitmapAttach();
	for (int i=0; i<_size.nPixels(); i++)
		_pBuff[i] = bitmap[i];
	shmdt (bitmap);
 
	SharedObject::detach (src);
}
 
/*
 * Commit data to shared object
 * shmID: id of shared object
 */
void SharedFrameBuffer::commit (int shmID)
{
#ifndef NDEBUG
	std::cerr<<"Commiting changes to shared object..\n";
#endif
	SharedObject *desc = SharedObject::attach (shmID);
 
	if (_size != desc->pFB()->_size)
	{
		// FB size changed
		desc->pFB()->_size = _size;
#ifndef NDEBUG
		std::cerr<<"Reallocating sahred bitmap (fb size changed)..\n";
#endif
		desc->bitmapFree ();
		desc->bitmapAlloc (_size);
	}
 
	// Copy selection (not needed by most of plugins)
	desc->pFB()->_select = _select;
 
	// Copy bitmap
	Pixel *bitmap = desc->bitmapAttach();
	for (int i=0; i<_size.nPixels(); i++)
		bitmap[i] = _pBuff[i];
	shmdt (bitmap);
 
	SharedObject::detach (desc);
}