<commit_before>/*************************************************************************
 *
 *  $RCSfile: drdefuno.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: nn $ $Date: 2001-03-05 11:31:09 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PCH
#include "ui_pch.hxx"
#endif

#pragma hdrstop

#include "drdefuno.hxx"
#include "docsh.hxx"
#include "drwlayer.hxx"

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

//------------------------------------------------------------------------

ScDrawDefaultsObj::ScDrawDefaultsObj(ScDocShell* pDocSh) :
    SvxUnoDrawPool( NULL ),
    pDocShell( pDocSh )
{
    //  SvxUnoDrawPool is initialized without model,
    //  draw layer is created on demand in getModelPool

    pDocShell->GetDocument()->AddUnoObject(*this);
}

ScDrawDefaultsObj::~ScDrawDefaultsObj()
{
    if (pDocShell)
        pDocShell->GetDocument()->RemoveUnoObject(*this);
}

void ScDrawDefaultsObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( SfxSimpleHint ) &&
            ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
    {
        pDocShell = NULL;       // document gone
    }
}

SfxItemPool* ScDrawDefaultsObj::getModelPool( sal_Bool bReadOnly ) throw()
{
    SfxItemPool* pRet = NULL;
    if ( pDocShell )
    {
        ScDrawLayer* pModel = bReadOnly ?
                        pDocShell->GetDocument()->GetDrawLayer() :
                        pDocShell->MakeDrawLayer();
        if ( pModel )
            pRet = &pModel->GetItemPool();
    }
    if ( !pRet )
        pRet = SvxUnoDrawPool::getModelPool( bReadOnly );       // uses default pool

    return pRet;
}

<commit_msg>#92075# excption specificaion<commit_after>/*************************************************************************
 *
 *  $RCSfile: drdefuno.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2001-09-18 15:12:49 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PCH
#include "ui_pch.hxx"
#endif

#pragma hdrstop

#include "drdefuno.hxx"
#include "docsh.hxx"
#include "drwlayer.hxx"

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

//------------------------------------------------------------------------

ScDrawDefaultsObj::ScDrawDefaultsObj(ScDocShell* pDocSh) :
    SvxUnoDrawPool( NULL ),
    pDocShell( pDocSh )
{
    //  SvxUnoDrawPool is initialized without model,
    //  draw layer is created on demand in getModelPool

    pDocShell->GetDocument()->AddUnoObject(*this);
}

ScDrawDefaultsObj::~ScDrawDefaultsObj() throw ()
{
    if (pDocShell)
        pDocShell->GetDocument()->RemoveUnoObject(*this);
}

void ScDrawDefaultsObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( SfxSimpleHint ) &&
            ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
    {
        pDocShell = NULL;       // document gone
    }
}

SfxItemPool* ScDrawDefaultsObj::getModelPool( sal_Bool bReadOnly ) throw()
{
    SfxItemPool* pRet = NULL;
    if ( pDocShell )
    {
        ScDrawLayer* pModel = bReadOnly ?
                        pDocShell->GetDocument()->GetDrawLayer() :
                        pDocShell->MakeDrawLayer();
        if ( pModel )
            pRet = &pModel->GetItemPool();
    }
    if ( !pRet )
        pRet = SvxUnoDrawPool::getModelPool( bReadOnly );       // uses default pool

    return pRet;
}

<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "vld.h"

#include <map>
#include "WorkerThread.h"
#include "Client.h"
#include "Server.h"
#include "libfastcgi/fastcgi.hpp"
#include "SelectThread.h"
#include "stringtools.h"
#include "Interface/File.h"

//#define EXTENSIVE_DEBUGGING

extern std::deque<CClient*> client_queue;
extern IMutex* clients_mutex;
extern ICondition* clients_cond;

CWorkerThread::CWorkerThread(CSelectThread *pMaster)
{
	stop_mutex=Server->createMutex();
	stop_cond=Server->createCondition();
	Master=pMaster;
	keep_alive=true;
	run=true;
}

CWorkerThread::~CWorkerThread()
{
  shutdown();
  Server->destroy(stop_cond);
  Server->destroy(stop_mutex);
}

void CWorkerThread::shutdown(void)
{
    IScopedLock slock(stop_mutex);
    Server->Log("waiting for worker...");
    run=false;
    clients_cond->notify_all();
    stop_cond->wait(&slock);
    Server->Log("done.");
}

void CWorkerThread::operator()()
{
	while(run)
	{
		size_t nq=0;
		IScopedLock lock(clients_mutex);

		while(client_queue.size()==0 )
		{
			clients_cond->wait(&lock);
			if(!run)
			{
			  IScopedLock slock(stop_mutex);
			  stop_cond->notify_one();
			  return;
			}
		}

		{
			while( client_queue.size()>0 )
			{
				char buffer[WT_BUFFERSIZE];
				CClient *client=client_queue[0];
				client_queue.erase(client_queue.begin());
				SOCKET s=client->getSocket();

				clients_mutex->Unlock();

				_i32 rc=recv(s, buffer, WT_BUFFERSIZE, MSG_NOSIGNAL);

				if( rc<1 )
				{
					keep_alive=true;
					Server->Log("Client disconnected", LL_INFO);
					Master->RemoveClient( client );
					clients_mutex->Lock();
				}
				else
				{
#ifdef EXTENSIVE_DEBUGGING
					std::string lbuf;
					for(_i32 i=0;i<rc;++i)
					{
						if( buffer[i]==0 )
							lbuf+='#';
						else
							lbuf+=buffer[i];
					}
					Server->Log("Incoming data: "+lbuf, LL_INFO);
#endif
					client->lock();
					client->getFCGIProtocolDriver()->process_input(buffer, rc);

					FCGIRequest* req=client->getFCGIProtocolDriver()->get_request();
					client->unlock();

					if( req!=NULL )
						client->addRequest(req);

					while( (req=client->getAndRemoveReadyRequest())!=NULL )
					{
						Server->addRequest();
						client->lock();
						ProcessRequest(client, req);
						client->unlock();
					}

					if( keep_alive==false )
					{
						keep_alive=true;
						Server->Log("Client disconnected", LL_INFO);
						Master->RemoveClient( client );
					}
					else
					{
						client->setProcessing(false);
						Master->WakeUp();
					}

					clients_mutex->Lock();
				}
			}
		}
	}
	IScopedLock slock(stop_mutex);
	stop_cond->notify_one();
}

void CWorkerThread::ProcessRequest(CClient *client, FCGIRequest *req)
{
	if( req->keep_connection )
	{
		keep_alive=true;
	}
	else
	{
		keep_alive=false;
	}

	if( req->role != FCGIRequest::RESPONDER )
	{
		Server->Log("Role ist not Responder", LL_ERROR);
		return;
	}

	str_map GET,POST;

	str_nmap::iterator iter=req->params.find("QUERY_STRING");
	if( iter!=req->params.end() )
	{
		for(size_t i=0,size=iter->second.size();i<size;++i)
		{
			if( iter->second[i]=='+' )
				iter->second[i]=' ';
		}
		ParseParamStr(iter->second, &GET );
		req->params.erase( iter );
	}

	std::string ct=req->params["CONTENT_TYPE"];
	std::string lct=ct;
	strlower(lct);
	bool postfile=false;
	POSTFILE_KEY pfkey;
	if(lct.find("multipart/form-data")==std::string::npos)
	{
		if( req->stdin_stream.size()>0 && req->stdin_stream.size()<1048576 )
		{
			for(size_t i=0,size=req->stdin_stream.size();i<size;++i)
			{
				if( req->stdin_stream[i]=='+' )
					req->stdin_stream[i]=' ';
			}
			ParseParamStr(req->stdin_stream, &POST );
		}
	}
	else
	{
		std::string boundary=getafter("boundary=",ct);
		pfkey=ParseMultipartData(req->stdin_stream, boundary);
	        req->params["POSTFILEKEY"]=nconvert(pfkey);
	        postfile=true;
	}

	str_map::iterator iter2=GET.find(L"a");

	if( iter2!=GET.end() )
	{
		int starttime=Server->getTimeMS();

		str_map::iterator iter3=GET.find(L"c");

		std::wstring context;
		if( iter3!=GET.end() )
			context=iter3->second;

		THREAD_ID tid=Server->Execute(iter2->second, context, GET, POST, req->params, req );

		if( tid==0 )
		{
			std::wstring error=L"Error: Unknown action ["+iter2->second+L"]";
			Server->Log(error, LL_WARNING);
			req->write("Content-type: text/html; charset=UTF-8\r\n\r\n"+wnarrow(error));
		}

		starttime=Server->getTimeMS()-starttime;
		Server->Log("Execution Time: "+nconvert(starttime)+" ms - time="+nconvert(Server->getTimeMS() ), LL_INFO);
	}
	else
	{
		std::string error="Error: Parameter 'action' not given.";
		req->write("Content-type: text/html; charset=UTF-8\r\n\r\n"+error);
	}

	if(postfile)
	{
		Server->clearPostFiles(pfkey);
	}

	req->end_request(0, FCGIRequest::REQUEST_COMPLETE);
}

POSTFILE_KEY CWorkerThread::ParseMultipartData(const std::string &data, const std::string &boundary)
{
	std::string rboundary="--"+boundary;
	int state=0;
	std::string key;
	std::string value;
	std::string filename;
	std::string name;
	std::string filedata;
	std::string contenttype;
	size_t start;
	POSTFILE_KEY pfilekey=Server->getPostFileKey();
	for(size_t i=0;i<data.size();++i)
	{
	    switch(state)
	    {
		case 0:
		    if(next(data,i,rboundary))
		    {
				i+=rboundary.size()+1;
				state=2;
		    }
		    break;
		case 1:
		    if(data[i]=='\n' || data[i]=='\r' )
			{
				if(data[i]=='\n')
				{
					state=4;
					rboundary+="--";
					start=i+1;
				}
				else
					break;
			}
		    else
				state=1;
		case 2:
			if(data[i]!=':')
				key+=toupper(data[i]);
		    else
				state=3;
		    break;
		case 3:
		    if(data[i]!='\n' && data[i]!='\r' )
				value+=data[i];
		    else if(data[i]=='\n')
			{
				if(key=="CONTENT-DISPOSITION")
				{
					name=getbetween("name=\"","\"", value);
					filename=getbetween("filename=\"","\"", value);
				}
				else if(key=="CONTENT-TYPE")
				{
					contenttype=value;
				}
				value.clear();
				key.clear();
				state=1;
			}
		    break;
		case 4:
			if(next(data,i,rboundary)==true)
			{
            	IFile *memfile=Server->openMemoryFile();
				memfile->Write(data.substr(start,i-start-2) );
				memfile->Seek(0);
				Server->addPostFile(pfilekey, name, SPostfile(memfile, widen(filename), widen(contenttype)) );
				state=0;
				rboundary.erase(rboundary.size()-2,2);
				i+=rboundary.size()+2;
				state=0;
			}
	    }
	}
    return pfilekey;
}<commit_msg>Catch exception if fcgi stream is invalid<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "vld.h"

#include <map>
#include "WorkerThread.h"
#include "Client.h"
#include "Server.h"
#include "libfastcgi/fastcgi.hpp"
#include "SelectThread.h"
#include "stringtools.h"
#include "Interface/File.h"

//#define EXTENSIVE_DEBUGGING

extern std::deque<CClient*> client_queue;
extern IMutex* clients_mutex;
extern ICondition* clients_cond;

CWorkerThread::CWorkerThread(CSelectThread *pMaster)
{
	stop_mutex=Server->createMutex();
	stop_cond=Server->createCondition();
	Master=pMaster;
	keep_alive=true;
	run=true;
}

CWorkerThread::~CWorkerThread()
{
  shutdown();
  Server->destroy(stop_cond);
  Server->destroy(stop_mutex);
}

void CWorkerThread::shutdown(void)
{
    IScopedLock slock(stop_mutex);
    Server->Log("waiting for worker...");
    run=false;
    clients_cond->notify_all();
    stop_cond->wait(&slock);
    Server->Log("done.");
}

void CWorkerThread::operator()()
{
	while(run)
	{
		size_t nq=0;
		IScopedLock lock(clients_mutex);

		while(client_queue.size()==0 )
		{
			clients_cond->wait(&lock);
			if(!run)
			{
			  IScopedLock slock(stop_mutex);
			  stop_cond->notify_one();
			  return;
			}
		}

		{
			while( client_queue.size()>0 )
			{
				char buffer[WT_BUFFERSIZE];
				CClient *client=client_queue[0];
				client_queue.erase(client_queue.begin());
				SOCKET s=client->getSocket();

				clients_mutex->Unlock();

				_i32 rc=recv(s, buffer, WT_BUFFERSIZE, MSG_NOSIGNAL);

				if( rc<1 )
				{
					keep_alive=true;
					Server->Log("Client disconnected", LL_INFO);
					Master->RemoveClient( client );
					clients_mutex->Lock();
				}
				else
				{
#ifdef EXTENSIVE_DEBUGGING
					std::string lbuf;
					for(_i32 i=0;i<rc;++i)
					{
						if( buffer[i]==0 )
							lbuf+='#';
						else
							lbuf+=buffer[i];
					}
					Server->Log("Incoming data: "+lbuf, LL_INFO);
#endif
					client->lock();
					try
					{
						client->getFCGIProtocolDriver()->process_input(buffer, rc);
					}catch(...){}

					FCGIRequest* req=NULL;
					try
					{
						req=client->getFCGIProtocolDriver()->get_request();
					}catch(...){}

					client->unlock();

					if( req!=NULL )
						client->addRequest(req);

					while( (req=client->getAndRemoveReadyRequest())!=NULL )
					{
						Server->addRequest();
						client->lock();
						ProcessRequest(client, req);
						client->unlock();
					}

					if( keep_alive==false )
					{
						keep_alive=true;
						Server->Log("Client disconnected", LL_INFO);
						Master->RemoveClient( client );
					}
					else
					{
						client->setProcessing(false);
						Master->WakeUp();
					}

					clients_mutex->Lock();
				}
			}
		}
	}
	IScopedLock slock(stop_mutex);
	stop_cond->notify_one();
}

void CWorkerThread::ProcessRequest(CClient *client, FCGIRequest *req)
{
	if( req->keep_connection )
	{
		keep_alive=true;
	}
	else
	{
		keep_alive=false;
	}

	if( req->role != FCGIRequest::RESPONDER )
	{
		Server->Log("Role ist not Responder", LL_ERROR);
		return;
	}

	str_map GET,POST;

	str_nmap::iterator iter=req->params.find("QUERY_STRING");
	if( iter!=req->params.end() )
	{
		for(size_t i=0,size=iter->second.size();i<size;++i)
		{
			if( iter->second[i]=='+' )
				iter->second[i]=' ';
		}
		ParseParamStr(iter->second, &GET );
		req->params.erase( iter );
	}

	std::string ct=req->params["CONTENT_TYPE"];
	std::string lct=ct;
	strlower(lct);
	bool postfile=false;
	POSTFILE_KEY pfkey;
	if(lct.find("multipart/form-data")==std::string::npos)
	{
		if( req->stdin_stream.size()>0 && req->stdin_stream.size()<1048576 )
		{
			for(size_t i=0,size=req->stdin_stream.size();i<size;++i)
			{
				if( req->stdin_stream[i]=='+' )
					req->stdin_stream[i]=' ';
			}
			ParseParamStr(req->stdin_stream, &POST );
		}
	}
	else
	{
		std::string boundary=getafter("boundary=",ct);
		pfkey=ParseMultipartData(req->stdin_stream, boundary);
	        req->params["POSTFILEKEY"]=nconvert(pfkey);
	        postfile=true;
	}

	str_map::iterator iter2=GET.find(L"a");

	if( iter2!=GET.end() )
	{
		int starttime=Server->getTimeMS();

		str_map::iterator iter3=GET.find(L"c");

		std::wstring context;
		if( iter3!=GET.end() )
			context=iter3->second;

		THREAD_ID tid=Server->Execute(iter2->second, context, GET, POST, req->params, req );

		if( tid==0 )
		{
			std::wstring error=L"Error: Unknown action ["+iter2->second+L"]";
			Server->Log(error, LL_WARNING);
			req->write("Content-type: text/html; charset=UTF-8\r\n\r\n"+wnarrow(error));
		}

		starttime=Server->getTimeMS()-starttime;
		Server->Log("Execution Time: "+nconvert(starttime)+" ms - time="+nconvert(Server->getTimeMS() ), LL_INFO);
	}
	else
	{
		std::string error="Error: Parameter 'action' not given.";
		req->write("Content-type: text/html; charset=UTF-8\r\n\r\n"+error);
	}

	if(postfile)
	{
		Server->clearPostFiles(pfkey);
	}

	req->end_request(0, FCGIRequest::REQUEST_COMPLETE);
}

POSTFILE_KEY CWorkerThread::ParseMultipartData(const std::string &data, const std::string &boundary)
{
	std::string rboundary="--"+boundary;
	int state=0;
	std::string key;
	std::string value;
	std::string filename;
	std::string name;
	std::string filedata;
	std::string contenttype;
	size_t start;
	POSTFILE_KEY pfilekey=Server->getPostFileKey();
	for(size_t i=0;i<data.size();++i)
	{
	    switch(state)
	    {
		case 0:
		    if(next(data,i,rboundary))
		    {
				i+=rboundary.size()+1;
				state=2;
		    }
		    break;
		case 1:
		    if(data[i]=='\n' || data[i]=='\r' )
			{
				if(data[i]=='\n')
				{
					state=4;
					rboundary+="--";
					start=i+1;
				}
				else
					break;
			}
		    else
				state=1;
		case 2:
			if(data[i]!=':')
				key+=toupper(data[i]);
		    else
				state=3;
		    break;
		case 3:
		    if(data[i]!='\n' && data[i]!='\r' )
				value+=data[i];
		    else if(data[i]=='\n')
			{
				if(key=="CONTENT-DISPOSITION")
				{
					name=getbetween("name=\"","\"", value);
					filename=getbetween("filename=\"","\"", value);
				}
				else if(key=="CONTENT-TYPE")
				{
					contenttype=value;
				}
				value.clear();
				key.clear();
				state=1;
			}
		    break;
		case 4:
			if(next(data,i,rboundary)==true)
			{
            	IFile *memfile=Server->openMemoryFile();
				memfile->Write(data.substr(start,i-start-2) );
				memfile->Seek(0);
				Server->addPostFile(pfilekey, name, SPostfile(memfile, widen(filename), widen(contenttype)) );
				state=0;
				rboundary.erase(rboundary.size()-2,2);
				i+=rboundary.size()+2;
				state=0;
			}
	    }
	}
    return pfilekey;
}<|endoftext|>


<commit_before>/*!
 *  Copyright (c) 2016 by Contributors
 * \file infer_shape.cc
 * \brief Inference the shapes given existin information.
 */
#include <nnvm/pass.h>
#include <nnvm/op_attr_types.h>
#include <nnvm/graph_attr_types.h>

namespace nnvm {
namespace pass {
namespace {

template<typename AttrType, typename IsNone, typename FDefault>
Graph InferAttr(Graph &&ret,
                const AttrType empty_val,
                const char* infer_name,
                const char* input_name,
                const char* attr_key_name,
                const char* attr_name,
                const char* unknown_name,
                IsNone fis_none,
                FDefault fdefault) {
  using AttrVector = std::vector<AttrType>;
  const IndexedGraph& idx = ret.indexed_graph();
  static auto& finfer_shape =
      Op::GetAttr<FInferNodeEntryAttr<AttrType> >(infer_name);
  static auto& is_backward =
      Op::GetAttr<TIsBackward>("TIsBackward");
  // gradient function, used to get node correspondence.
  static auto& fgrad =
      Op::GetAttr<FGradient>("FGradient");
  // reshape shape vector
  AttrVector rshape;
  if (ret.attrs.count(attr_name) != 0) {
    rshape = ret.MoveCopyAttr<AttrVector>(attr_name);
  } else {
    rshape.resize(idx.num_node_entries(), empty_val);
  }

  if (ret.attrs.count(input_name) != 0) {
    const AttrVector& shape_args = ret.GetAttr<AttrVector>(input_name);
    CHECK_LE(shape_args.size(), idx.input_nodes().size())
        << "More provided shapes than number of arguments.";
    for (size_t i = 0; i < shape_args.size(); ++i) {
      rshape[idx.entry_id(idx.input_nodes()[i], 0)] = shape_args[i];
    }
    // erase the provided arguments
    ret.attrs.erase(input_name);
  }

  // get the shape hints
  std::string shape_hints_key = std::string(attr_name) + "_hints";
  if (ret.attrs.count(shape_hints_key)) {
    NodeEntryMap<AttrType> shape_hints =
      ret.GetAttr<NodeEntryMap<AttrType>>(shape_hints_key);
    for (const auto& kv : shape_hints) {
      NodeEntry e = kv.first;
      if (idx.exist(e.node.get())) {
        rshape[idx.entry_id(kv.first)] = kv.second;
      }
    }
  }

  std::string shape_attr_key;
  if (ret.attrs.count(attr_key_name) != 0) {
    shape_attr_key = ret.GetAttr<std::string>(attr_key_name);
    // erase the provided arguments
    ret.attrs.erase(attr_key_name);
  }
  // Temp space for shape inference.
  std::vector<AttrType> ishape, oshape;

  // inference step function for nid
  auto infer_step = [&](uint32_t nid, bool last_iter) {
    const auto& inode = idx[nid];
    const uint32_t num_inputs = inode.inputs.size();
    const uint32_t num_outputs = inode.source->num_outputs();
    if (inode.source->is_variable()) {
      // Variable node. No operator. Only one output entry.
      CHECK(inode.source->op() == nullptr);
      CHECK_EQ(num_outputs, 1U);
      const uint32_t out_ent_id = idx.entry_id(nid, 0);
      if (shape_attr_key.length() != 0 && fis_none(rshape[out_ent_id])) {
        auto it = inode.source->attrs.dict.find(shape_attr_key);
        if (it != inode.source->attrs.dict.end()) {
          std::istringstream is(it->second);
          CHECK(is >> rshape[out_ent_id]) << "Invalid attribute";
        }
      }
    } else if (is_backward.get(inode.source->op(), false) && inode.control_deps.size()) {
      CHECK_GE(inode.control_deps.size(), 1U)
        << "BackwardOp need to have control_deps to its forward op";
      const IndexedGraph::Node& fnode = idx[inode.control_deps[0]];
      NodePtr fwd_ptr = inode.source->control_deps[0];
      CHECK(fwd_ptr->op() != nullptr) << "Forward op cannot be a variable";
      // use gradient function to find out the correspondence.
      std::vector<NodeEntry> ograd(fwd_ptr->num_outputs());
      for (size_t i = 0; i < ograd.size(); ++i) {
        ograd[i].index = static_cast<uint32_t>(i);
      }
      // input gradient list
      auto igrad = fgrad[fwd_ptr->op()](fwd_ptr, ograd);
      const Node* igrad_node = nullptr;
      // Input gradient assignement
      for (size_t i = 0; i < igrad.size(); ++i) {
        if (igrad[i].node->op() == inode.source->op()) {
          uint32_t eid = idx.entry_id(nid, igrad[i].index);
          if (fis_none(rshape[eid])) {
            rshape[eid] = rshape[idx.entry_id(fnode.inputs[i])];
          } else {
            CHECK_EQ(rshape[eid], rshape[idx.entry_id(fnode.inputs[i])])
                << "Backward shape inconsistent with the forward shape";
          }
          if (igrad_node == nullptr) {
            igrad_node = igrad[i].node.get();
          } else {
            CHECK(igrad_node == igrad[i].node.get());
          }
        }
      }
      // out grad entries
      CHECK(igrad_node != nullptr)
        << "Cannot find matching backward op for " << inode.source->attrs.name;
      for (size_t i = 0; i < igrad_node->inputs.size(); ++i) {
        const NodeEntry& e = igrad_node->inputs[i];
        if (e.node == nullptr) {
          uint32_t eid = idx.entry_id(inode.inputs[i]);
          if (fis_none(rshape[eid])) {
            rshape[eid] = rshape[idx.entry_id(inode.control_deps[0], e.index)];
          }
        }
      }
    } else {
      bool forward_known = true;
      // Forward operator inference.
      ishape.resize(num_inputs, empty_val);
      for (uint32_t i = 0; i < ishape.size(); ++i) {
        ishape[i] = rshape[idx.entry_id(inode.inputs[i])];
        if (fis_none(ishape[i])) forward_known = false;
      }
      oshape.resize(num_outputs, empty_val);
      for (uint32_t i = 0; i < oshape.size(); ++i) {
        oshape[i] = rshape[idx.entry_id(nid, i)];
        if (fis_none(oshape[i])) forward_known = false;
      }
      auto finfer = finfer_shape.get(inode.source->op(), fdefault);
      if (!forward_known) {
        if (finfer != nullptr) {
          // Call inference function of the operator.
          try {
            forward_known = finfer(inode.source->attrs, &ishape, &oshape);
          } catch (const std::exception& e) {
            throw dmlc::Error("Error in operator " + inode.source->attrs.name + ": " + e.what());
          }
        } else {
          CHECK(!last_iter)
              << "Attribute " << infer_name
              << " is not registed by op " << inode.source->op()->name
              << " we are not able to complete the inference because of this";
        }
      }
      // Save to the result map.
      for (uint32_t i = 0; i < num_inputs; ++i) {
        rshape[idx.entry_id(inode.inputs[i])] = ishape[i];
      }
      for (uint32_t i = 0; i < num_outputs; ++i) {
        rshape[idx.entry_id(nid, i)] = oshape[i];
      }
    }
  };

  size_t last_num_unknown;
  size_t num_unknown = rshape.size();
  int i = 0;
  do {
    if (i % 2 == 0) {
      for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
        infer_step(nid, false);
      }
    } else {
      // backward inference
      for (uint32_t i = idx.num_nodes(); i != 0; --i) {
        infer_step(i - 1, false);
      }
    }
    last_num_unknown = num_unknown;
    num_unknown = 0;
    for (size_t j = 0; j < idx.num_node_entries(); ++j) {
      if (fis_none(rshape[j])) {
        ++num_unknown;
      }
    }
    ++i;
  } while (num_unknown > 0 && last_num_unknown > num_unknown);
  // set the shapes
  ret.attrs[attr_name] = std::make_shared<any>(std::move(rshape));
  // number of nodes who knows the shape.
  ret.attrs[unknown_name] = std::make_shared<any>(num_unknown);
  return ret;
}

NNVM_REGISTER_PASS(InferShape)
.describe("Infer the shape of each node entries.")
.set_body([](Graph ret) {
    return InferAttr<TShape>(
        std::move(ret), TShape(),
        "FInferShape", "shape_inputs", "shape_attr_key",
        "shape", "shape_num_unknown_nodes",
        [](const TShape& s) { return s.ndim() == 0 || s.Size() == 0; },
        nullptr);
  })
.set_change_graph(false)
.provide_graph_attr("shape");

// inference fucntion for same type
inline bool SameType(const NodeAttrs& attrs,
                     std::vector<int> *iattr,
                     std::vector<int> *oattr) {
  int def_v = -1;
  for (int v : *oattr) {
    if (v != -1) {
      def_v = v; break;
    }
  }
  if (def_v == -1) {
    for (int v : *iattr) {
      if (v != -1) {
        def_v = v; break;
      }
    }
  }
  if (def_v == -1) return false;
  for (int& v : *oattr) {
    v = def_v;
  }
  for (int& v : *iattr) {
    v = def_v;
  }
  return true;
}

NNVM_REGISTER_PASS(InferType)
.describe("Infer the dtype of each node entries.")
.set_body([](Graph ret) {
    return InferAttr<int>(
        std::move(ret), -1,
        "FInferType", "dtype_inputs", "dtype_attr_key",
        "dtype", "dtype_num_unknown_nodes",
        [](const int t) { return t == -1; },
        SameType);
  })
.set_change_graph(false)
.provide_graph_attr("dtype");

DMLC_JSON_ENABLE_ANY(ShapeVector, list_shape);
DMLC_JSON_ENABLE_ANY(DTypeVector, list_int);
DMLC_JSON_ENABLE_ANY(size_t, size_t);

}  // namespace
}  // namespace pass
}  // namespace nnvm
<commit_msg>Fix infer shape bug (#148)<commit_after>/*!
 *  Copyright (c) 2016 by Contributors
 * \file infer_shape.cc
 * \brief Inference the shapes given existin information.
 */
#include <nnvm/pass.h>
#include <nnvm/op_attr_types.h>
#include <nnvm/graph_attr_types.h>

namespace nnvm {
namespace pass {
namespace {

template<typename AttrType, typename IsNone, typename FDefault>
Graph InferAttr(Graph &&ret,
                const AttrType empty_val,
                const char* infer_name,
                const char* input_name,
                const char* attr_key_name,
                const char* attr_name,
                const char* unknown_name,
                IsNone fis_none,
                FDefault fdefault) {
  using AttrVector = std::vector<AttrType>;
  const IndexedGraph& idx = ret.indexed_graph();
  static auto& finfer_shape =
      Op::GetAttr<FInferNodeEntryAttr<AttrType> >(infer_name);
  static auto& is_backward =
      Op::GetAttr<TIsBackward>("TIsBackward");
  // gradient function, used to get node correspondence.
  static auto& fgrad =
      Op::GetAttr<FGradient>("FGradient");
  // reshape shape vector
  AttrVector rshape;
  if (ret.attrs.count(attr_name) != 0) {
    rshape = ret.MoveCopyAttr<AttrVector>(attr_name);
  } else {
    rshape.resize(idx.num_node_entries(), empty_val);
  }

  if (ret.attrs.count(input_name) != 0) {
    const AttrVector& shape_args = ret.GetAttr<AttrVector>(input_name);
    CHECK_LE(shape_args.size(), idx.input_nodes().size())
        << "More provided shapes than number of arguments.";
    for (size_t i = 0; i < shape_args.size(); ++i) {
      rshape[idx.entry_id(idx.input_nodes()[i], 0)] = shape_args[i];
    }
    // erase the provided arguments
    ret.attrs.erase(input_name);
  }

  // get the shape hints
  std::string shape_hints_key = std::string(attr_name) + "_hints";
  if (ret.attrs.count(shape_hints_key)) {
    NodeEntryMap<AttrType> shape_hints =
      ret.GetAttr<NodeEntryMap<AttrType>>(shape_hints_key);
    for (const auto& kv : shape_hints) {
      NodeEntry e = kv.first;
      if (idx.exist(e.node.get())) {
        rshape[idx.entry_id(kv.first)] = kv.second;
      }
    }
  }

  std::string shape_attr_key;
  if (ret.attrs.count(attr_key_name) != 0) {
    shape_attr_key = ret.GetAttr<std::string>(attr_key_name);
    // erase the provided arguments
    ret.attrs.erase(attr_key_name);
  }
  // Temp space for shape inference.
  std::vector<AttrType> ishape, oshape;

  // inference step function for nid
  auto infer_step = [&](uint32_t nid, bool last_iter) {
    const auto& inode = idx[nid];
    const uint32_t num_inputs = inode.inputs.size();
    const uint32_t num_outputs = inode.source->num_outputs();
    if (inode.source->is_variable()) {
      // Variable node. No operator. Only one output entry.
      CHECK(inode.source->op() == nullptr);
      CHECK_EQ(num_outputs, 1U);
      const uint32_t out_ent_id = idx.entry_id(nid, 0);
      if (shape_attr_key.length() != 0 && fis_none(rshape[out_ent_id])) {
        auto it = inode.source->attrs.dict.find(shape_attr_key);
        if (it != inode.source->attrs.dict.end()) {
          std::istringstream is(it->second);
          CHECK(is >> rshape[out_ent_id]) << "Invalid attribute";
        }
      }
    } else if (is_backward.get(inode.source->op(), false) && inode.control_deps.size()) {
      CHECK_GE(inode.control_deps.size(), 1U)
        << "BackwardOp need to have control_deps to its forward op";
      const IndexedGraph::Node& fnode = idx[inode.control_deps[0]];
      NodePtr fwd_ptr = inode.source->control_deps[0];
      CHECK(fwd_ptr->op() != nullptr) << "Forward op cannot be a variable";
      // use gradient function to find out the correspondence.
      std::vector<NodeEntry> ograd(fwd_ptr->num_outputs());
      for (size_t i = 0; i < ograd.size(); ++i) {
        ograd[i].index = static_cast<uint32_t>(i);
      }
      // input gradient list
      auto igrad = fgrad[fwd_ptr->op()](fwd_ptr, ograd);
      const Node* igrad_node = nullptr;
      // Input gradient assignement
      for (size_t i = 0; i < igrad.size(); ++i) {
        if (igrad[i].node->op() == inode.source->op()) {
          uint32_t eid = idx.entry_id(nid, igrad[i].index);
          if (fis_none(rshape[eid])) {
            rshape[eid] = rshape[idx.entry_id(fnode.inputs[i])];
          } else if (!fis_none(rshape[idx.entry_id(fnode.inputs[i])])) {
            CHECK_EQ(rshape[eid], rshape[idx.entry_id(fnode.inputs[i])])
                << "Backward shape inconsistent with the forward shape";
          }
          if (igrad_node == nullptr) {
            igrad_node = igrad[i].node.get();
          } else {
            CHECK(igrad_node == igrad[i].node.get());
          }
        }
      }
      // out grad entries
      CHECK(igrad_node != nullptr)
        << "Cannot find matching backward op for " << inode.source->attrs.name;
      for (size_t i = 0; i < igrad_node->inputs.size(); ++i) {
        const NodeEntry& e = igrad_node->inputs[i];
        if (e.node == nullptr) {
          uint32_t eid = idx.entry_id(inode.inputs[i]);
          if (fis_none(rshape[eid])) {
            rshape[eid] = rshape[idx.entry_id(inode.control_deps[0], e.index)];
          }
        }
      }
    } else {
      bool forward_known = true;
      // Forward operator inference.
      ishape.resize(num_inputs, empty_val);
      for (uint32_t i = 0; i < ishape.size(); ++i) {
        ishape[i] = rshape[idx.entry_id(inode.inputs[i])];
        if (fis_none(ishape[i])) forward_known = false;
      }
      oshape.resize(num_outputs, empty_val);
      for (uint32_t i = 0; i < oshape.size(); ++i) {
        oshape[i] = rshape[idx.entry_id(nid, i)];
        if (fis_none(oshape[i])) forward_known = false;
      }
      auto finfer = finfer_shape.get(inode.source->op(), fdefault);
      if (!forward_known) {
        if (finfer != nullptr) {
          // Call inference function of the operator.
          try {
            forward_known = finfer(inode.source->attrs, &ishape, &oshape);
          } catch (const std::exception& e) {
            throw dmlc::Error("Error in operator " + inode.source->attrs.name + ": " + e.what());
          }
        } else {
          CHECK(!last_iter)
              << "Attribute " << infer_name
              << " is not registed by op " << inode.source->op()->name
              << " we are not able to complete the inference because of this";
        }
      }
      // Save to the result map.
      for (uint32_t i = 0; i < num_inputs; ++i) {
        rshape[idx.entry_id(inode.inputs[i])] = ishape[i];
      }
      for (uint32_t i = 0; i < num_outputs; ++i) {
        rshape[idx.entry_id(nid, i)] = oshape[i];
      }
    }
  };

  size_t last_num_unknown;
  size_t num_unknown = rshape.size();
  int i = 0;
  do {
    if (i % 2 == 0) {
      for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
        infer_step(nid, false);
      }
    } else {
      // backward inference
      for (uint32_t i = idx.num_nodes(); i != 0; --i) {
        infer_step(i - 1, false);
      }
    }
    last_num_unknown = num_unknown;
    num_unknown = 0;
    for (size_t j = 0; j < idx.num_node_entries(); ++j) {
      if (fis_none(rshape[j])) {
        ++num_unknown;
      }
    }
    ++i;
  } while (num_unknown > 0 && last_num_unknown > num_unknown);
  // set the shapes
  ret.attrs[attr_name] = std::make_shared<any>(std::move(rshape));
  // number of nodes who knows the shape.
  ret.attrs[unknown_name] = std::make_shared<any>(num_unknown);
  return ret;
}

NNVM_REGISTER_PASS(InferShape)
.describe("Infer the shape of each node entries.")
.set_body([](Graph ret) {
    return InferAttr<TShape>(
        std::move(ret), TShape(),
        "FInferShape", "shape_inputs", "shape_attr_key",
        "shape", "shape_num_unknown_nodes",
        [](const TShape& s) { return s.ndim() == 0 || s.Size() == 0; },
        nullptr);
  })
.set_change_graph(false)
.provide_graph_attr("shape");

// inference fucntion for same type
inline bool SameType(const NodeAttrs& attrs,
                     std::vector<int> *iattr,
                     std::vector<int> *oattr) {
  int def_v = -1;
  for (int v : *oattr) {
    if (v != -1) {
      def_v = v; break;
    }
  }
  if (def_v == -1) {
    for (int v : *iattr) {
      if (v != -1) {
        def_v = v; break;
      }
    }
  }
  if (def_v == -1) return false;
  for (int& v : *oattr) {
    v = def_v;
  }
  for (int& v : *iattr) {
    v = def_v;
  }
  return true;
}

NNVM_REGISTER_PASS(InferType)
.describe("Infer the dtype of each node entries.")
.set_body([](Graph ret) {
    return InferAttr<int>(
        std::move(ret), -1,
        "FInferType", "dtype_inputs", "dtype_attr_key",
        "dtype", "dtype_num_unknown_nodes",
        [](const int t) { return t == -1; },
        SameType);
  })
.set_change_graph(false)
.provide_graph_attr("dtype");

DMLC_JSON_ENABLE_ANY(ShapeVector, list_shape);
DMLC_JSON_ENABLE_ANY(DTypeVector, list_int);
DMLC_JSON_ENABLE_ANY(size_t, size_t);

}  // namespace
}  // namespace pass
}  // namespace nnvm
<|endoftext|>


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

#include "module.h"

#include <err.h>

#include <iostream>

namespace dfm {

Module::Module() : name(DEFAULT_MODULE_NAMES)
{
}

Module::Module(const std::string& name) : name(name)
{
}

const std::string&
Module::getName() const
{
    return name;
}

void
Module::setName(const std::string& name)
{
    this->name = name;
}

bool
Module::install(const std::string& sourceDirectory) const
{
    for (const auto& file : files) {
        std::shared_ptr<InstallAction> installAction =
            file.createInstallAction(sourceDirectory);
        if (!installAction->performAction()) {
            warnx("Failed to perform install action \"%s\".",
                installAction->getName().c_str());
            return false;
        }
    }
    for (const auto& action : installActions) {
        bool status = action->performAction();
        if (!status) {
            warnx("Failed to perform install action \"%s\".",
                action->getName().c_str());
            return false;
        }
    }
    return true;
}

bool
Module::uninstall(const std::string& sourceDirectory) const
{
    for (const auto& file : files) {
        std::shared_ptr<RemoveAction> uninstallAction =
            file.createUninstallAction();
        if (!uninstallAction->performAction()) {
            warnx("Failed to perform uninstall action \"%s\".",
                uninstallAction->getName().c_str());
            return false;
        }
    }
    for (const auto& action : uninstallActions) {
        bool status = action->performAction();
        if (!status) {
            warnx("Failed to perform uninstall action \"%s\".",
                action->getName().c_str());
            return false;
        }
    }
    return true;
}

bool
Module::update(const std::string& sourceDirectory) const
{
    for (const auto& file : files) {
        std::shared_ptr<FileCheckAction> updateAction =
            file.createUpdateAction(sourceDirectory);
        if (!updateAction->performAction()) {
            warnx("Failed to perform update action \"%s\".",
                updateAction->getName().c_str());
            return false;
        }
    }
    for (const auto& action : updateActions) {
        bool status = action->performAction();
        if (!status) {
            warnx("Failed to perform update action \"%s\".",
                action->getName().c_str());
            return false;
        }
    }
    return true;
}

void
Module::addInstallAction(std::shared_ptr<ModuleAction> action)
{
    installActions.push_back(action);
}

void
Module::addUninstallAction(std::shared_ptr<ModuleAction> action)
{
    uninstallActions.push_back(action);
}

void
Module::addUpdateAction(std::shared_ptr<ModuleAction> action)
{
    updateActions.push_back(action);
}

const std::vector<std::shared_ptr<ModuleAction>>&
Module::getInstallActions() const
{
    return installActions;
}

const std::vector<std::shared_ptr<ModuleAction>>&
Module::getUninstallActions() const
{
    return uninstallActions;
}

const std::vector<std::shared_ptr<ModuleAction>>&
Module::getUpdateActions() const
{
    return updateActions;
}

void
Module::addFile(const std::string& filename)
{
    files.push_back(ModuleFile(filename));
}

void
Module::addFile(
    const std::string& filename, const std::string& destinationDirectory)
{
    files.push_back(ModuleFile(filename, destinationDirectory));
}

void
Module::addFile(const std::string& filename,
    const std::string& destinationDirectory,
    const std::string& destinationFilename)
{
    files.push_back(
        ModuleFile(filename, destinationDirectory, destinationFilename));
}

const std::vector<ModuleFile>
Module::getFiles() const
{
    return files;
}

std::vector<std::string>
Module::createConfigLines() const
{
    std::vector<std::string> lines;
    lines.push_back(name + ":");
    for (const auto& file : files)
        lines.push_back("\t" + file.createConfigLines()[0]);
    if (installActions.size() > 0)
        lines.push_back("install:");
    /*
     * It would make more sense to include this type of block in the if
     * statement above it but this way leads to less indentation.
     */
    for (const auto& action : installActions) {
        for (const auto& line : action->createConfigLines())
            lines.push_back("\t" + line);
    }
    if (uninstallActions.size() > 0)
        lines.push_back("uninstall:");
    for (const auto& action : uninstallActions) {
        for (const auto& line : action->createConfigLines())
            lines.push_back("\t" + line);
    }
    if (updateActions.size() > 0)
        lines.push_back("update:");
    for (const auto& action : updateActions) {
        for (const auto& line : action->createConfigLines())
            lines.push_back("\t" + line);
    }
    return lines;
}
} /* namespace dfm */
<commit_msg>Incorporated small code change from gdfm<commit_after>/*
 * Copyright (c) 2016 Jason Waataja
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "module.h"

#include <err.h>

namespace dfm {

Module::Module() : name(DEFAULT_MODULE_NAMES)
{
}

Module::Module(const std::string& name) : name(name)
{
}

const std::string&
Module::getName() const
{
    return name;
}

void
Module::setName(const std::string& name)
{
    this->name = name;
}

bool
Module::install(const std::string& sourceDirectory) const
{
    for (const auto& file : files) {
        std::shared_ptr<InstallAction> installAction =
            file.createInstallAction(sourceDirectory);
        if (!installAction->performAction()) {
            warnx("Failed to perform install action \"%s\".",
                installAction->getName().c_str());
            return false;
        }
    }
    for (const auto& action : installActions) {
        if (action->performAction()) {
            warnx("Failed to perform install action \"%s\".",
                action->getName().c_str());
            return false;
        }
    }
    return true;
}

bool
Module::uninstall(const std::string& sourceDirectory) const
{
    for (const auto& file : files) {
        std::shared_ptr<RemoveAction> uninstallAction =
            file.createUninstallAction();
        if (!uninstallAction->performAction()) {
            warnx("Failed to perform uninstall action \"%s\".",
                uninstallAction->getName().c_str());
            return false;
        }
    }
    for (const auto& action : uninstallActions) {
        if (action->performAction()) {
            warnx("Failed to perform uninstall action \"%s\".",
                action->getName().c_str());
            return false;
        }
    }
    return true;
}

bool
Module::update(const std::string& sourceDirectory) const
{
    for (const auto& file : files) {
        std::shared_ptr<FileCheckAction> updateAction =
            file.createUpdateAction(sourceDirectory);
        if (!updateAction->performAction()) {
            warnx("Failed to perform update action \"%s\".",
                updateAction->getName().c_str());
            return false;
        }
    }
    for (const auto& action : updateActions) {
        if (action->performAction()) {
            warnx("Failed to perform update action \"%s\".",
                action->getName().c_str());
            return false;
        }
    }
    return true;
}

void
Module::addInstallAction(std::shared_ptr<ModuleAction> action)
{
    installActions.push_back(action);
}

void
Module::addUninstallAction(std::shared_ptr<ModuleAction> action)
{
    uninstallActions.push_back(action);
}

void
Module::addUpdateAction(std::shared_ptr<ModuleAction> action)
{
    updateActions.push_back(action);
}

const std::vector<std::shared_ptr<ModuleAction>>&
Module::getInstallActions() const
{
    return installActions;
}

const std::vector<std::shared_ptr<ModuleAction>>&
Module::getUninstallActions() const
{
    return uninstallActions;
}

const std::vector<std::shared_ptr<ModuleAction>>&
Module::getUpdateActions() const
{
    return updateActions;
}

void
Module::addFile(const std::string& filename)
{
    files.push_back(ModuleFile(filename));
}

void
Module::addFile(
    const std::string& filename, const std::string& destinationDirectory)
{
    files.push_back(ModuleFile(filename, destinationDirectory));
}

void
Module::addFile(const std::string& filename,
    const std::string& destinationDirectory,
    const std::string& destinationFilename)
{
    files.push_back(
        ModuleFile(filename, destinationDirectory, destinationFilename));
}

const std::vector<ModuleFile>
Module::getFiles() const
{
    return files;
}

std::vector<std::string>
Module::createConfigLines() const
{
    std::vector<std::string> lines;
    lines.push_back(name + ":");
    for (const auto& file : files)
        lines.push_back("\t" + file.createConfigLines()[0]);
    if (installActions.size() > 0)
        lines.push_back("install:");
    /*
     * It would make more sense to include this type of block in the if
     * statement above it but this way leads to less indentation.
     */
    for (const auto& action : installActions) {
        for (const auto& line : action->createConfigLines())
            lines.push_back("\t" + line);
    }
    if (uninstallActions.size() > 0)
        lines.push_back("uninstall:");
    for (const auto& action : uninstallActions) {
        for (const auto& line : action->createConfigLines())
            lines.push_back("\t" + line);
    }
    if (updateActions.size() > 0)
        lines.push_back("update:");
    for (const auto& action : updateActions) {
        for (const auto& line : action->createConfigLines())
            lines.push_back("\t" + line);
    }
    return lines;
}
} /* namespace dfm */
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "directshowioreader.h"

#include "directshoweventloop.h"
#include "directshowglobal.h"
#include "directshowiosource.h"

#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qthread.h>

class DirectShowSampleRequest
{
public:
    DirectShowSampleRequest(
            IMediaSample *sample, DWORD_PTR userData, LONGLONG position, LONG length, BYTE *buffer)
        : next(0)
        , sample(sample)
        , userData(userData)
        , position(position)
        , length(length)
        , buffer(buffer)
        , result(S_FALSE)
    {
    }

    DirectShowSampleRequest *remove() { DirectShowSampleRequest *n = next; delete this; return n; }

    DirectShowSampleRequest *next;
    IMediaSample *sample;
    DWORD_PTR userData;
    LONGLONG position;
    LONG length;
    BYTE *buffer;
    HRESULT result;
};

DirectShowIOReader::DirectShowIOReader(
        QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop)
    : m_source(source)
    , m_device(device)
    , m_loop(loop)
    , m_pendingHead(0)
    , m_pendingTail(0)
    , m_readyHead(0)
    , m_readyTail(0)
    , m_synchronousPosition(0)
    , m_synchronousLength(0)
    , m_synchronousBytesRead(0)
    , m_synchronousBuffer(0)
    , m_synchronousResult(S_OK)
    , m_totalLength(0)
    , m_availableLength(0)
    , m_flushing(false)
{
    moveToThread(device->thread());

    connect(device, SIGNAL(readyRead()), this, SLOT(readyRead()));
}

DirectShowIOReader::~DirectShowIOReader()
{
    flushRequests();
}

HRESULT DirectShowIOReader::QueryInterface(REFIID riid, void **ppvObject)
{
    return m_source->QueryInterface(riid, ppvObject);
}

ULONG DirectShowIOReader::AddRef()
{
    return m_source->AddRef();
}

ULONG DirectShowIOReader::Release()
{
    return m_source->Release();
}

// IAsyncReader
HRESULT DirectShowIOReader::RequestAllocator(
        IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual)
{
    if (!ppActual || !pProps) {
        return E_POINTER;
    } else {
        ALLOCATOR_PROPERTIES actualProperties;

        if (pProps->cbAlign == 0)
            pProps->cbAlign = 1;

        if (pPreferred && pPreferred->SetProperties(pProps, &actualProperties) == S_OK) {
            pPreferred->AddRef();

            *ppActual = pPreferred;

            m_source->setAllocator(*ppActual);

            return S_OK;
        } else {
            *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator);

            if (*ppActual) {
                if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) {
                    (*ppActual)->Release();
                } else {
                    m_source->setAllocator(*ppActual);

                    return S_OK;
                }
            }
        }
        ppActual = 0;

        return E_FAIL;
    }
}

HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser)
{
    QMutexLocker locker(&m_mutex);

    if (!pSample) {
        return E_POINTER;
    } else if (m_flushing) {
        return VFW_E_WRONG_STATE;
    } else {
        REFERENCE_TIME startTime = 0;
        REFERENCE_TIME endTime = 0;
        BYTE *buffer;

        if (pSample->GetTime(&startTime, &endTime) != S_OK
                || pSample->GetPointer(&buffer) != S_OK) {
            return VFW_E_SAMPLE_TIME_NOT_SET;
        } else {
            LONGLONG position = startTime / 10000000;
            LONG length = ((endTime - startTime) / 10000000) + 1;

            DirectShowSampleRequest *request = new DirectShowSampleRequest(
                    pSample, dwUser, position, length, buffer);

            if (m_pendingTail) {
                m_pendingTail->next = request;
            } else {
                m_pendingHead = request;

                m_loop->postEvent(this, new QEvent(QEvent::User));
            }
            m_pendingTail = request;

            return S_OK;
        }
    }
}

HRESULT DirectShowIOReader::WaitForNext(
        DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser)
{
    if (!ppSample || !pdwUser)
        return E_POINTER;

    QMutexLocker locker(&m_mutex);

    do {
        if (m_readyHead) {
            DirectShowSampleRequest *request = m_readyHead;

            *ppSample = request->sample;
            *pdwUser = request->userData;

            HRESULT hr = request->result;

            m_readyHead = request->next;

            if (!m_readyHead)
                m_readyTail = 0;

            delete request;

            return hr;
        } else if (m_flushing) {
            *ppSample = 0;
            *pdwUser = 0;

            return VFW_E_WRONG_STATE;
        }
    } while (m_wait.wait(&m_mutex, dwTimeout));

    *ppSample = 0;
    *pdwUser = 0;

    return VFW_E_TIMEOUT;
}

HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample)
{
    if (!pSample) {
        return E_POINTER;
    } else {
        REFERENCE_TIME startTime = 0;
        REFERENCE_TIME endTime = 0;
        BYTE *buffer;

        if (pSample->GetTime(&startTime, &endTime) != S_OK
                || pSample->GetPointer(&buffer) != S_OK) {
            return VFW_E_SAMPLE_TIME_NOT_SET;
        } else {
            LONGLONG position = startTime / 10000000;
            LONG length = ((endTime - startTime) / 10000000) + 1;

            QMutexLocker locker(&m_mutex);

            if (thread() == QThread::currentThread()) {
                qint64 bytesRead = 0;

                HRESULT hr = blockingRead(position, length, buffer, &bytesRead);

                if (SUCCEEDED(hr))
                    pSample->SetActualDataLength(bytesRead);

                return hr;
            } else {
                m_synchronousPosition = position;
                m_synchronousLength = length;
                m_synchronousBuffer = buffer;

                m_loop->postEvent(this, new QEvent(QEvent::User));

                m_wait.wait(&m_mutex);

                m_synchronousBuffer = 0;

                if (SUCCEEDED(m_synchronousResult))
                    pSample->SetActualDataLength(m_synchronousBytesRead);

                return m_synchronousResult;
            }
        }
    }
}

HRESULT DirectShowIOReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer)
{
    if (!pBuffer) {
        return E_POINTER;
    } else {
        if (thread() == QThread::currentThread()) {
            qint64 bytesRead;

            return blockingRead(llPosition, lLength, pBuffer, &bytesRead);
        } else {
            QMutexLocker locker(&m_mutex);

            m_synchronousPosition = llPosition;
            m_synchronousLength = lLength;
            m_synchronousBuffer = pBuffer;

            m_loop->postEvent(this, new QEvent(QEvent::User));

            m_wait.wait(&m_mutex);

            m_synchronousBuffer = 0;

            return m_synchronousResult;
        }
    }
}

HRESULT DirectShowIOReader::Length(LONGLONG *pTotal, LONGLONG *pAvailable)
{
    if (!pTotal || !pAvailable) {
        return E_POINTER;
    } else {
        QMutexLocker locker(&m_mutex);

        *pTotal = m_totalLength;
        *pAvailable = m_availableLength;

        return S_OK;
    }
}

HRESULT DirectShowIOReader::BeginFlush()
{
    QMutexLocker locker(&m_mutex);

    if (m_flushing)
        return S_FALSE;

    m_flushing = true;

    flushRequests();

    m_wait.wakeAll();

    return S_OK;
}

HRESULT DirectShowIOReader::EndFlush()
{
    QMutexLocker locker(&m_mutex);

    if (!m_flushing)
        return S_FALSE;

    m_flushing = false;

    return S_OK;
}

void DirectShowIOReader::customEvent(QEvent *event)
{
    if (event->type() == QEvent::User) {
        readyRead();
    } else {
        QObject::customEvent(event);
    }
}

void DirectShowIOReader::readyRead()
{
    QMutexLocker locker(&m_mutex);

    m_availableLength = m_device->bytesAvailable() + m_device->pos();
    m_totalLength = m_device->size();

    if (m_synchronousBuffer) {
        if (nonBlockingRead(
                m_synchronousPosition,
                m_synchronousLength,
                m_synchronousBuffer,
                &m_synchronousBytesRead,
                &m_synchronousResult)) {
            m_wait.wakeAll();
        }
    } else {
        qint64 bytesRead = 0;

        while (m_pendingHead && nonBlockingRead(
                m_pendingHead->position,
                m_pendingHead->length,
                m_pendingHead->buffer,
                &bytesRead,
            &m_pendingHead->result)) {
            m_pendingHead->sample->SetActualDataLength(bytesRead);

            if (m_readyTail)
                m_readyTail->next = m_pendingHead;
            m_readyTail = m_pendingHead;

            m_pendingHead = m_pendingHead->next;

            m_readyTail->next = 0;

            if (!m_pendingHead)
                m_pendingTail = 0;

            if (!m_readyHead)
                m_readyHead = m_readyTail;

            m_wait.wakeAll();
        }
    }
}

HRESULT DirectShowIOReader::blockingRead(
        LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead)
{
    *bytesRead = 0;

    if (qint64(position) > m_device->size())
        return S_FALSE;

    const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);

    while (m_device->bytesAvailable() + m_device->pos() < maxSize) {
        if (!m_device->waitForReadyRead(-1))
            return S_FALSE;
    }

    if (m_device->pos() != position && !m_device->seek(position))
        return S_FALSE;

    const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());

    *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);

    if (*bytesRead != length) {
        qMemSet(buffer + *bytesRead, 0, length - *bytesRead);

        return S_FALSE;
    } else {
        return S_OK;
    }
}

bool DirectShowIOReader::nonBlockingRead(
        LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result)
{
    const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);

    if (position > m_device->size()) {
        *bytesRead = 0;
        *result = S_FALSE;

        return true;
    } else if (m_device->bytesAvailable() + m_device->pos() >= maxSize) {
        if (m_device->pos() != position && !m_device->seek(position)) {
            *bytesRead = 0;
            *result = S_FALSE;

            return true;
        } else {
            const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());

            *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);

            if (*bytesRead != length) {
                qMemSet(buffer + *bytesRead, 0, length - *bytesRead);

                *result = S_FALSE;
            } else {
                *result = S_OK;
            }

            return true;
        }
    } else {
        return false;
    }
}

void DirectShowIOReader::flushRequests()
{
    while (m_pendingHead) {
        m_pendingHead->result = VFW_E_WRONG_STATE;

        if (m_readyTail)
            m_readyTail->next = m_pendingHead;

        m_readyTail = m_pendingHead;

        m_pendingHead = m_pendingHead->next;

        m_readyTail->next = 0;

        if (!m_pendingHead)
            m_pendingTail = 0;

        if (!m_readyHead)
            m_readyHead = m_readyTail;
    }
}
<commit_msg>Fix incorrect buffer size calculation.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "directshowioreader.h"

#include "directshoweventloop.h"
#include "directshowglobal.h"
#include "directshowiosource.h"

#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qthread.h>

class DirectShowSampleRequest
{
public:
    DirectShowSampleRequest(
            IMediaSample *sample, DWORD_PTR userData, LONGLONG position, LONG length, BYTE *buffer)
        : next(0)
        , sample(sample)
        , userData(userData)
        , position(position)
        , length(length)
        , buffer(buffer)
        , result(S_FALSE)
    {
    }

    DirectShowSampleRequest *remove() { DirectShowSampleRequest *n = next; delete this; return n; }

    DirectShowSampleRequest *next;
    IMediaSample *sample;
    DWORD_PTR userData;
    LONGLONG position;
    LONG length;
    BYTE *buffer;
    HRESULT result;
};

DirectShowIOReader::DirectShowIOReader(
        QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop)
    : m_source(source)
    , m_device(device)
    , m_loop(loop)
    , m_pendingHead(0)
    , m_pendingTail(0)
    , m_readyHead(0)
    , m_readyTail(0)
    , m_synchronousPosition(0)
    , m_synchronousLength(0)
    , m_synchronousBytesRead(0)
    , m_synchronousBuffer(0)
    , m_synchronousResult(S_OK)
    , m_totalLength(0)
    , m_availableLength(0)
    , m_flushing(false)
{
    moveToThread(device->thread());

    connect(device, SIGNAL(readyRead()), this, SLOT(readyRead()));
}

DirectShowIOReader::~DirectShowIOReader()
{
    flushRequests();
}

HRESULT DirectShowIOReader::QueryInterface(REFIID riid, void **ppvObject)
{
    return m_source->QueryInterface(riid, ppvObject);
}

ULONG DirectShowIOReader::AddRef()
{
    return m_source->AddRef();
}

ULONG DirectShowIOReader::Release()
{
    return m_source->Release();
}

// IAsyncReader
HRESULT DirectShowIOReader::RequestAllocator(
        IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual)
{
    if (!ppActual || !pProps) {
        return E_POINTER;
    } else {
        ALLOCATOR_PROPERTIES actualProperties;

        if (pProps->cbAlign == 0)
            pProps->cbAlign = 1;

        if (pPreferred && pPreferred->SetProperties(pProps, &actualProperties) == S_OK) {
            pPreferred->AddRef();

            *ppActual = pPreferred;

            m_source->setAllocator(*ppActual);

            return S_OK;
        } else {
            *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator);

            if (*ppActual) {
                if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) {
                    (*ppActual)->Release();
                } else {
                    m_source->setAllocator(*ppActual);

                    return S_OK;
                }
            }
        }
        ppActual = 0;

        return E_FAIL;
    }
}

HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser)
{
    QMutexLocker locker(&m_mutex);

    if (!pSample) {
        return E_POINTER;
    } else if (m_flushing) {
        return VFW_E_WRONG_STATE;
    } else {
        REFERENCE_TIME startTime = 0;
        REFERENCE_TIME endTime = 0;
        BYTE *buffer;

        if (pSample->GetTime(&startTime, &endTime) != S_OK
                || pSample->GetPointer(&buffer) != S_OK) {
            return VFW_E_SAMPLE_TIME_NOT_SET;
        } else {
            LONGLONG position = startTime / 10000000;
            LONG length = (endTime - startTime) / 10000000;

            DirectShowSampleRequest *request = new DirectShowSampleRequest(
                    pSample, dwUser, position, length, buffer);

            if (m_pendingTail) {
                m_pendingTail->next = request;
            } else {
                m_pendingHead = request;

                m_loop->postEvent(this, new QEvent(QEvent::User));
            }
            m_pendingTail = request;

            return S_OK;
        }
    }
}

HRESULT DirectShowIOReader::WaitForNext(
        DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser)
{
    if (!ppSample || !pdwUser)
        return E_POINTER;

    QMutexLocker locker(&m_mutex);

    do {
        if (m_readyHead) {
            DirectShowSampleRequest *request = m_readyHead;

            *ppSample = request->sample;
            *pdwUser = request->userData;

            HRESULT hr = request->result;

            m_readyHead = request->next;

            if (!m_readyHead)
                m_readyTail = 0;

            delete request;

            return hr;
        } else if (m_flushing) {
            *ppSample = 0;
            *pdwUser = 0;

            return VFW_E_WRONG_STATE;
        }
    } while (m_wait.wait(&m_mutex, dwTimeout));

    *ppSample = 0;
    *pdwUser = 0;

    return VFW_E_TIMEOUT;
}

HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample)
{
    if (!pSample) {
        return E_POINTER;
    } else {
        REFERENCE_TIME startTime = 0;
        REFERENCE_TIME endTime = 0;
        BYTE *buffer;

        if (pSample->GetTime(&startTime, &endTime) != S_OK
                || pSample->GetPointer(&buffer) != S_OK) {
            return VFW_E_SAMPLE_TIME_NOT_SET;
        } else {
            LONGLONG position = startTime / 10000000;
            LONG length = (endTime - startTime) / 10000000;

            QMutexLocker locker(&m_mutex);

            if (thread() == QThread::currentThread()) {
                qint64 bytesRead = 0;

                HRESULT hr = blockingRead(position, length, buffer, &bytesRead);

                if (SUCCEEDED(hr))
                    pSample->SetActualDataLength(bytesRead);

                return hr;
            } else {
                m_synchronousPosition = position;
                m_synchronousLength = length;
                m_synchronousBuffer = buffer;

                m_loop->postEvent(this, new QEvent(QEvent::User));

                m_wait.wait(&m_mutex);

                m_synchronousBuffer = 0;

                if (SUCCEEDED(m_synchronousResult))
                    pSample->SetActualDataLength(m_synchronousBytesRead);

                return m_synchronousResult;
            }
        }
    }
}

HRESULT DirectShowIOReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer)
{
    if (!pBuffer) {
        return E_POINTER;
    } else {
        if (thread() == QThread::currentThread()) {
            qint64 bytesRead;

            return blockingRead(llPosition, lLength, pBuffer, &bytesRead);
        } else {
            QMutexLocker locker(&m_mutex);

            m_synchronousPosition = llPosition;
            m_synchronousLength = lLength;
            m_synchronousBuffer = pBuffer;

            m_loop->postEvent(this, new QEvent(QEvent::User));

            m_wait.wait(&m_mutex);

            m_synchronousBuffer = 0;

            return m_synchronousResult;
        }
    }
}

HRESULT DirectShowIOReader::Length(LONGLONG *pTotal, LONGLONG *pAvailable)
{
    if (!pTotal || !pAvailable) {
        return E_POINTER;
    } else {
        QMutexLocker locker(&m_mutex);

        *pTotal = m_totalLength;
        *pAvailable = m_availableLength;

        return S_OK;
    }
}

HRESULT DirectShowIOReader::BeginFlush()
{
    QMutexLocker locker(&m_mutex);

    if (m_flushing)
        return S_FALSE;

    m_flushing = true;

    flushRequests();

    m_wait.wakeAll();

    return S_OK;
}

HRESULT DirectShowIOReader::EndFlush()
{
    QMutexLocker locker(&m_mutex);

    if (!m_flushing)
        return S_FALSE;

    m_flushing = false;

    return S_OK;
}

void DirectShowIOReader::customEvent(QEvent *event)
{
    if (event->type() == QEvent::User) {
        readyRead();
    } else {
        QObject::customEvent(event);
    }
}

void DirectShowIOReader::readyRead()
{
    QMutexLocker locker(&m_mutex);

    m_availableLength = m_device->bytesAvailable() + m_device->pos();
    m_totalLength = m_device->size();

    if (m_synchronousBuffer) {
        if (nonBlockingRead(
                m_synchronousPosition,
                m_synchronousLength,
                m_synchronousBuffer,
                &m_synchronousBytesRead,
                &m_synchronousResult)) {
            m_wait.wakeAll();
        }
    } else {
        qint64 bytesRead = 0;

        while (m_pendingHead && nonBlockingRead(
                m_pendingHead->position,
                m_pendingHead->length,
                m_pendingHead->buffer,
                &bytesRead,
            &m_pendingHead->result)) {
            m_pendingHead->sample->SetActualDataLength(bytesRead);

            if (m_readyTail)
                m_readyTail->next = m_pendingHead;
            m_readyTail = m_pendingHead;

            m_pendingHead = m_pendingHead->next;

            m_readyTail->next = 0;

            if (!m_pendingHead)
                m_pendingTail = 0;

            if (!m_readyHead)
                m_readyHead = m_readyTail;

            m_wait.wakeAll();
        }
    }
}

HRESULT DirectShowIOReader::blockingRead(
        LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead)
{
    *bytesRead = 0;

    if (qint64(position) > m_device->size())
        return S_FALSE;

    const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);

    while (m_device->bytesAvailable() + m_device->pos() < maxSize) {
        if (!m_device->waitForReadyRead(-1))
            return S_FALSE;
    }

    if (m_device->pos() != position && !m_device->seek(position))
        return S_FALSE;

    const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());

    *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);

    if (*bytesRead != length) {
        qMemSet(buffer + *bytesRead, 0, length - *bytesRead);

        return S_FALSE;
    } else {
        return S_OK;
    }
}

bool DirectShowIOReader::nonBlockingRead(
        LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result)
{
    const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);

    if (position > m_device->size()) {
        *bytesRead = 0;
        *result = S_FALSE;

        return true;
    } else if (m_device->bytesAvailable() + m_device->pos() >= maxSize) {
        if (m_device->pos() != position && !m_device->seek(position)) {
            *bytesRead = 0;
            *result = S_FALSE;

            return true;
        } else {
            const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());

            *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);

            if (*bytesRead != length) {
                qMemSet(buffer + *bytesRead, 0, length - *bytesRead);

                *result = S_FALSE;
            } else {
                *result = S_OK;
            }

            return true;
        }
    } else {
        return false;
    }
}

void DirectShowIOReader::flushRequests()
{
    while (m_pendingHead) {
        m_pendingHead->result = VFW_E_WRONG_STATE;

        if (m_readyTail)
            m_readyTail->next = m_pendingHead;

        m_readyTail = m_pendingHead;

        m_pendingHead = m_pendingHead->next;

        m_readyTail->next = 0;

        if (!m_pendingHead)
            m_pendingTail = 0;

        if (!m_readyHead)
            m_readyHead = m_readyTail;
    }
}
<|endoftext|>