<commit_before>/*
 Copyright (C) 2015 Vladimir "allejo" Jimenez

 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 <sstream>

#include "../../src/bzfs/bzfs.h"
#include "bzfsAPI.h"

// Define plug-in name
const std::string PLUGIN_NAME = "Master Baiter";

// Define plug-in version numbering
const int MAJOR = 1;
const int MINOR = 0;
const int REV = 0;
const int BUILD = 1;

class MatchTrainerAssistant : public bz_Plugin, public bz_CustomSlashCommandHandler
{
public:
    virtual const char* Name ();
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);

    virtual bool SlashCommand (int playerID, bz_ApiString, bz_ApiString, bz_APIStringList*);

    bool  handleSpawn[256];
    float lastDeaths[256][4];
};

BZ_PLUGIN(MatchTrainerAssistant)

const char* MatchTrainerAssistant::Name (void)
{
    static std::string pluginBuild = "";

    if (!pluginBuild.size())
    {
        std::ostringstream pluginBuildStream;

        pluginBuildStream << PLUGIN_NAME << " " << MAJOR << "." << MINOR << "." << REV << " (" << BUILD << ")";
        pluginBuild = pluginBuildStream.str();
    }

    return pluginBuild.c_str();
}

void MatchTrainerAssistant::Init (const char* commandLine)
{
    // Register our events with Register()
    Register(bz_eGetPlayerSpawnPosEvent);
    Register(bz_ePlayerDieEvent);

    // Register our custom slash commands
    bz_registerCustomSlashCommand("spawn", this);
    bz_registerCustomSlashCommand("flag", this);
    bz_registerCustomSlashCommand("die", this);
}

void MatchTrainerAssistant::Cleanup (void)
{
    Flush(); // Clean up all the events

    // Clean up our custom slash commands
    bz_removeCustomSlashCommand("spawn");
    bz_removeCustomSlashCommand("flag");
    bz_removeCustomSlashCommand("die");
}

void MatchTrainerAssistant::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eGetPlayerSpawnPosEvent: // This event is called each time the server needs a new spawn postion
        {
            bz_GetPlayerSpawnPosEventData_V1* spawnData = (bz_GetPlayerSpawnPosEventData_V1*)eventData;

            if (handleSpawn[spawnData->playerID])
            {
                spawnData->handled = handleSpawn[spawnData->playerID];
                spawnData->pos[0]  = lastDeaths[spawnData->playerID][0];
                spawnData->pos[1]  = lastDeaths[spawnData->playerID][1];
                spawnData->pos[2]  = lastDeaths[spawnData->playerID][2];
                spawnData->rot     = lastDeaths[spawnData->playerID][3];

                handleSpawn[spawnData->playerID] = false;
            }
        }
        break;

        case bz_ePlayerDieEvent: // This event is called each time a tank is killed.
        {
            bz_PlayerDieEventData_V1* dieData = (bz_PlayerDieEventData_V1*)eventData;

            lastDeaths[dieData->playerID][0] = dieData->state.pos[0];
            lastDeaths[dieData->playerID][1] = dieData->state.pos[1];
            lastDeaths[dieData->playerID][2] = dieData->state.pos[2];
            lastDeaths[dieData->playerID][3] = dieData->state.rotation;
        }
        break;

        default: break;
    }
}

bool MatchTrainerAssistant::SlashCommand(int playerID, bz_ApiString command, bz_ApiString /*message*/, bz_APIStringList *params)
{
    std::unique_ptr<bz_BasePlayerRecord> pr(bz_getPlayerByIndex(playerID));

    if (command == "spawn")
    {
        if (pr->team == eObservers)
        {
            bz_sendTextMessage(BZ_SERVER, playerID, "Only players may execute this command.");
            return true;
        }

        if (pr->spawned)
        {
            bz_killPlayer(playerID, BZ_SERVER);
        }

        if (params->size() > 0)
        {
            if (params->size() != 1 && params->size() != 4)
            {
                bz_sendTextMessage(BZ_SERVER, playerID, "Spawn Command Usage");
                bz_sendTextMessage(BZ_SERVER, playerID, "---");
                bz_sendTextMessage(BZ_SERVER, playerID, "/spawn");
                bz_sendTextMessage(BZ_SERVER, playerID, "   - Respawn at the location of your last death");
                bz_sendTextMessage(BZ_SERVER, playerID, "/spawn <id|callsign>");
                bz_sendTextMessage(BZ_SERVER, playerID, "   - Respawn at the location of another player's location or location of death");
                bz_sendTextMessage(BZ_SERVER, playerID, "/spawn <x> <y> <z> <rotation>");
                bz_sendTextMessage(BZ_SERVER, playerID, "   - Respawn at specified location; don't spawn inside a building!");

                return true;
            }
            else if (params->size() == 1)
            {
                std::unique_ptr<bz_BasePlayerRecord> target(bz_getPlayerBySlotOrCallsign(params->get(0).c_str()));

                lastDeaths[playerID][0] = target->lastKnownState.pos[0];
                lastDeaths[playerID][1] = target->lastKnownState.pos[1];
                lastDeaths[playerID][2] = target->lastKnownState.pos[2];
                lastDeaths[playerID][3] = target->lastKnownState.rotation;
            }
            else
            {
                lastDeaths[playerID][0] = std::atoi(params->get(0).c_str());
                lastDeaths[playerID][1] = std::atoi(params->get(1).c_str());
                lastDeaths[playerID][2] = std::atoi(params->get(2).c_str());
                lastDeaths[playerID][3] = std::atoi(params->get(3).c_str());
            }
        }

        playerAlive(playerID);
        handleSpawn[playerID] = true;

        return true;
    }
    else if (command == "flag")
    {
        return false;
    }
    else if (command == "die")
    {
        bz_killPlayer(playerID, BZ_SERVER);

        return true;
    }

    return false;
}
<commit_msg>Fix copy paste typo<commit_after>/*
 Copyright (C) 2015 Vladimir "allejo" Jimenez

 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 <sstream>

#include "../../src/bzfs/bzfs.h"
#include "bzfsAPI.h"

// Define plug-in name
const std::string PLUGIN_NAME = "Match Trainer Assistant";

// Define plug-in version numbering
const int MAJOR = 1;
const int MINOR = 0;
const int REV = 0;
const int BUILD = 1;

class MatchTrainerAssistant : public bz_Plugin, public bz_CustomSlashCommandHandler
{
public:
    virtual const char* Name ();
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);

    virtual bool SlashCommand (int playerID, bz_ApiString, bz_ApiString, bz_APIStringList*);

    bool  handleSpawn[256];
    float lastDeaths[256][4];
};

BZ_PLUGIN(MatchTrainerAssistant)

const char* MatchTrainerAssistant::Name (void)
{
    static std::string pluginBuild = "";

    if (!pluginBuild.size())
    {
        std::ostringstream pluginBuildStream;

        pluginBuildStream << PLUGIN_NAME << " " << MAJOR << "." << MINOR << "." << REV << " (" << BUILD << ")";
        pluginBuild = pluginBuildStream.str();
    }

    return pluginBuild.c_str();
}

void MatchTrainerAssistant::Init (const char* commandLine)
{
    // Register our events with Register()
    Register(bz_eGetPlayerSpawnPosEvent);
    Register(bz_ePlayerDieEvent);

    // Register our custom slash commands
    bz_registerCustomSlashCommand("spawn", this);
    bz_registerCustomSlashCommand("flag", this);
    bz_registerCustomSlashCommand("die", this);
}

void MatchTrainerAssistant::Cleanup (void)
{
    Flush(); // Clean up all the events

    // Clean up our custom slash commands
    bz_removeCustomSlashCommand("spawn");
    bz_removeCustomSlashCommand("flag");
    bz_removeCustomSlashCommand("die");
}

void MatchTrainerAssistant::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eGetPlayerSpawnPosEvent: // This event is called each time the server needs a new spawn postion
        {
            bz_GetPlayerSpawnPosEventData_V1* spawnData = (bz_GetPlayerSpawnPosEventData_V1*)eventData;

            if (handleSpawn[spawnData->playerID])
            {
                spawnData->handled = handleSpawn[spawnData->playerID];
                spawnData->pos[0]  = lastDeaths[spawnData->playerID][0];
                spawnData->pos[1]  = lastDeaths[spawnData->playerID][1];
                spawnData->pos[2]  = lastDeaths[spawnData->playerID][2];
                spawnData->rot     = lastDeaths[spawnData->playerID][3];

                handleSpawn[spawnData->playerID] = false;
            }
        }
        break;

        case bz_ePlayerDieEvent: // This event is called each time a tank is killed.
        {
            bz_PlayerDieEventData_V1* dieData = (bz_PlayerDieEventData_V1*)eventData;

            lastDeaths[dieData->playerID][0] = dieData->state.pos[0];
            lastDeaths[dieData->playerID][1] = dieData->state.pos[1];
            lastDeaths[dieData->playerID][2] = dieData->state.pos[2];
            lastDeaths[dieData->playerID][3] = dieData->state.rotation;
        }
        break;

        default: break;
    }
}

bool MatchTrainerAssistant::SlashCommand(int playerID, bz_ApiString command, bz_ApiString /*message*/, bz_APIStringList *params)
{
    std::unique_ptr<bz_BasePlayerRecord> pr(bz_getPlayerByIndex(playerID));

    if (command == "spawn")
    {
        if (pr->team == eObservers)
        {
            bz_sendTextMessage(BZ_SERVER, playerID, "Only players may execute this command.");
            return true;
        }

        if (pr->spawned)
        {
            bz_killPlayer(playerID, BZ_SERVER);
        }

        if (params->size() > 0)
        {
            if (params->size() != 1 && params->size() != 4)
            {
                bz_sendTextMessage(BZ_SERVER, playerID, "Spawn Command Usage");
                bz_sendTextMessage(BZ_SERVER, playerID, "---");
                bz_sendTextMessage(BZ_SERVER, playerID, "/spawn");
                bz_sendTextMessage(BZ_SERVER, playerID, "   - Respawn at the location of your last death");
                bz_sendTextMessage(BZ_SERVER, playerID, "/spawn <id|callsign>");
                bz_sendTextMessage(BZ_SERVER, playerID, "   - Respawn at the location of another player's location or location of death");
                bz_sendTextMessage(BZ_SERVER, playerID, "/spawn <x> <y> <z> <rotation>");
                bz_sendTextMessage(BZ_SERVER, playerID, "   - Respawn at specified location; don't spawn inside a building!");

                return true;
            }
            else if (params->size() == 1)
            {
                std::unique_ptr<bz_BasePlayerRecord> target(bz_getPlayerBySlotOrCallsign(params->get(0).c_str()));

                lastDeaths[playerID][0] = target->lastKnownState.pos[0];
                lastDeaths[playerID][1] = target->lastKnownState.pos[1];
                lastDeaths[playerID][2] = target->lastKnownState.pos[2];
                lastDeaths[playerID][3] = target->lastKnownState.rotation;
            }
            else
            {
                lastDeaths[playerID][0] = std::atoi(params->get(0).c_str());
                lastDeaths[playerID][1] = std::atoi(params->get(1).c_str());
                lastDeaths[playerID][2] = std::atoi(params->get(2).c_str());
                lastDeaths[playerID][3] = std::atoi(params->get(3).c_str());
            }
        }

        playerAlive(playerID);
        handleSpawn[playerID] = true;

        return true;
    }
    else if (command == "flag")
    {
        return false;
    }
    else if (command == "die")
    {
        bz_killPlayer(playerID, BZ_SERVER);

        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [axtam].
 *
 * The Initial Developer of the Original Code is Mozilla Corp.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Mark Hammond
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
#include "axtam.h"
#include "COMErrorClass.h"
#include "ExcepInfo.h"

namespace axtam
{
	/* *sob* - tamarin throws exceptions if I try and define this in the base class
	BEGIN_NATIVE_MAP(COMErrorClass)
		NATIVE_METHOD(axtam_com_Error_getErrorMessage, COMErrorClass::getErrorMessage)
	END_NATIVE_MAP()
	*/

	COMErrorClass::COMErrorClass(VTable* cvtable)
		: ClassClosure(cvtable)
	{
//		AvmAssert(traits()->sizeofInstance == sizeof(COMErrorClass));
//		prototype = createInstance(ivtable(), toplevel()->objectClass->prototype);
	}

	void COMErrorClass::throwError(HRESULT hr, EXCEPINFO *pei /* = NULL */)
	{
		AXTam *core = (AXTam *)this->core();
		Atom args[] = { nullObjectAtom, core->intToAtom(hr), pei ? core->excepinfoClass->create(pei)->atom() : nullObjectAtom };
		core->throwAtom(construct(2, args));
	}

	Stringp COMErrorClass::getErrorMessage(int errorID) const
	{
		DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
		wchar *buffer;
		if (::FormatMessageW(flags, 0, errorID, 0, (LPWSTR)&buffer, 0, NULL )<=0)
			return this->core()->constantString("FormatMessage failed!");
		// FormatMessage always sticks a trailing \r\n.
		size_t len = wcslen((wchar_t *)buffer);
		if (len > 2)
			buffer[len-2] = '\0';
		Stringp ret = core()->newString(buffer);
		LocalFree(buffer);
		return ret;
	}

	// override ctor just so we can get 'hresult' :(
	Atom COMErrorClass::construct(int argc, Atom* argv)
	{
		Atom ret = ClassClosure::construct(argc, argv);
		AvmAssert(argc>=1);
		AvmAssert(core()->istype(ret, traits()->itraits));
		COMErrorObject *o = (COMErrorObject *)core()->atomToScriptObject(ret);
		o->atomhresult = argv[1];
		return ret;
	}

	COMErrorObject::COMErrorObject(VTable* vtable,
							 ScriptObject *delegate)
		: ScriptObject(vtable, delegate), atomhresult(0)
	{
		AvmAssert(traits()->sizeofInstance == sizeof(COMErrorObject));

		#ifdef DEBUGGER
		AvmCore *core = this->core();
		// Copy the stack trace
		stackTrace = core->newStackTrace();
		#endif
	}

	HRESULT COMErrorObject::getHRESULT() const
	{
		// *sob* - why can't I fetch it from the instance?
		// XXX - fixme
		// Atom r = getStringProperty(core()->constantString("hresult"));
		const Atom &r = atomhresult;
		return (HRESULT)core()->toUInt32(r);
	}
	// the subclasses.
	// COMConsumerErrorClass
	BEGIN_NATIVE_MAP(COMConsumerErrorClass)
		NATIVE_METHOD(axtam_com_ConsumerError_getErrorMessage, COMErrorClass::getErrorMessage)
	END_NATIVE_MAP()
	COMConsumerErrorClass::COMConsumerErrorClass(VTable* cvtable)
		: COMErrorClass(cvtable)
	{
		AvmAssert(traits()->sizeofInstance == sizeof(COMConsumerErrorClass));
		prototype = createInstance(ivtable(), toplevel()->objectClass->prototype);

		AXTam* core = (AXTam*)this->core();
		if (!core->comConsumerErrorClass)
			core->comConsumerErrorClass = this;
	}

	ScriptObject* COMConsumerErrorClass::createInstance(VTable *ivtable,
														ScriptObject *prototype)
	{
		return new (ivtable->gc(), ivtable->getExtraSize()) COMConsumerErrorObject(ivtable, prototype);
	}

	// COMProviderErrorClass
	BEGIN_NATIVE_MAP(COMProviderErrorClass)
		NATIVE_METHOD(axtam_com_ProviderError_getErrorMessage, COMErrorClass::getErrorMessage)
	END_NATIVE_MAP()

	COMProviderErrorClass::COMProviderErrorClass(VTable* cvtable)
		: COMErrorClass(cvtable)
	{
		AvmAssert(traits()->sizeofInstance == sizeof(COMProviderErrorClass));
		prototype = createInstance(ivtable(), toplevel()->objectClass->prototype);
		AXTam* core = (AXTam*)this->core();
		if (!core->comProviderErrorClass)
			core->comProviderErrorClass = this;
	}

	ScriptObject* COMProviderErrorClass::createInstance(VTable *ivtable,
														ScriptObject *prototype)
	{
		return new (ivtable->gc(), ivtable->getExtraSize()) COMProviderErrorObject(ivtable, prototype);
	}

}
<commit_msg>Return an empty string if FormatMessage() fails.<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [axtam].
 *
 * The Initial Developer of the Original Code is Mozilla Corp.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Mark Hammond
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
#include "axtam.h"
#include "COMErrorClass.h"
#include "ExcepInfo.h"

namespace axtam
{
	/* *sob* - tamarin throws exceptions if I try and define this in the base class
	BEGIN_NATIVE_MAP(COMErrorClass)
		NATIVE_METHOD(axtam_com_Error_getErrorMessage, COMErrorClass::getErrorMessage)
	END_NATIVE_MAP()
	*/

	COMErrorClass::COMErrorClass(VTable* cvtable)
		: ClassClosure(cvtable)
	{
//		AvmAssert(traits()->sizeofInstance == sizeof(COMErrorClass));
//		prototype = createInstance(ivtable(), toplevel()->objectClass->prototype);
	}

	void COMErrorClass::throwError(HRESULT hr, EXCEPINFO *pei /* = NULL */)
	{
		AXTam *core = (AXTam *)this->core();
		Atom args[] = { nullObjectAtom, core->intToAtom(hr), pei ? core->excepinfoClass->create(pei)->atom() : nullObjectAtom };
		core->throwAtom(construct(2, args));
	}

	Stringp COMErrorClass::getErrorMessage(int errorID) const
	{
		DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
		wchar *buffer;
		if (::FormatMessageW(flags, 0, errorID, 0, (LPWSTR)&buffer, 0, NULL )<=0)
			return core()->kEmptyString;
		// FormatMessage always sticks a trailing \r\n.
		size_t len = wcslen((wchar_t *)buffer);
		if (len > 2)
			buffer[len-2] = '\0';
		Stringp ret = core()->newString(buffer);
		LocalFree(buffer);
		return ret;
	}

	// override ctor just so we can get 'hresult' :(
	Atom COMErrorClass::construct(int argc, Atom* argv)
	{
		Atom ret = ClassClosure::construct(argc, argv);
		AvmAssert(argc>=1);
		AvmAssert(core()->istype(ret, traits()->itraits));
		COMErrorObject *o = (COMErrorObject *)core()->atomToScriptObject(ret);
		o->atomhresult = argv[1];
		return ret;
	}

	COMErrorObject::COMErrorObject(VTable* vtable,
							 ScriptObject *delegate)
		: ScriptObject(vtable, delegate), atomhresult(0)
	{
		AvmAssert(traits()->sizeofInstance == sizeof(COMErrorObject));

		#ifdef DEBUGGER
		AvmCore *core = this->core();
		// Copy the stack trace
		stackTrace = core->newStackTrace();
		#endif
	}

	HRESULT COMErrorObject::getHRESULT() const
	{
		// *sob* - why can't I fetch it from the instance?
		// XXX - fixme
		// Atom r = getStringProperty(core()->constantString("hresult"));
		const Atom &r = atomhresult;
		return (HRESULT)core()->toUInt32(r);
	}
	// the subclasses.
	// COMConsumerErrorClass
	BEGIN_NATIVE_MAP(COMConsumerErrorClass)
		NATIVE_METHOD(axtam_com_ConsumerError_getErrorMessage, COMErrorClass::getErrorMessage)
	END_NATIVE_MAP()
	COMConsumerErrorClass::COMConsumerErrorClass(VTable* cvtable)
		: COMErrorClass(cvtable)
	{
		AvmAssert(traits()->sizeofInstance == sizeof(COMConsumerErrorClass));
		prototype = createInstance(ivtable(), toplevel()->objectClass->prototype);

		AXTam* core = (AXTam*)this->core();
		if (!core->comConsumerErrorClass)
			core->comConsumerErrorClass = this;
	}

	ScriptObject* COMConsumerErrorClass::createInstance(VTable *ivtable,
														ScriptObject *prototype)
	{
		return new (ivtable->gc(), ivtable->getExtraSize()) COMConsumerErrorObject(ivtable, prototype);
	}

	// COMProviderErrorClass
	BEGIN_NATIVE_MAP(COMProviderErrorClass)
		NATIVE_METHOD(axtam_com_ProviderError_getErrorMessage, COMErrorClass::getErrorMessage)
	END_NATIVE_MAP()

	COMProviderErrorClass::COMProviderErrorClass(VTable* cvtable)
		: COMErrorClass(cvtable)
	{
		AvmAssert(traits()->sizeofInstance == sizeof(COMProviderErrorClass));
		prototype = createInstance(ivtable(), toplevel()->objectClass->prototype);
		AXTam* core = (AXTam*)this->core();
		if (!core->comProviderErrorClass)
			core->comProviderErrorClass = this;
	}

	ScriptObject* COMProviderErrorClass::createInstance(VTable *ivtable,
														ScriptObject *prototype)
	{
		return new (ivtable->gc(), ivtable->getExtraSize()) COMProviderErrorObject(ivtable, prototype);
	}

}
<|endoftext|>


<commit_before>#include <bits/stdc++.h>
#define dd(x) cout << #x << ": " << x << endl;
#define optimize_ios ios_base::sync_with_stdio(0);cin.tie(0);
#define MAXN 1000002
#define MOD 21092013
#define PB push_back
#define MP make_pair
#define NODE first.first
#define PARENT first.second
#define LEFT second.first
#define RIGHT second.second
#define ALL(x) x.begin(), x.end()
#define INF -1
#define L 0
#define R 1
using namespace std;
typedef stack<bool> stackbl;
typedef stack<int> stacki;
typedef vector<bool> vectorbl;

string S, T;
stackbl ParentDirections;
vectorbl ChildrenDirections;
stacki MovsLater;
bool direction;
int DP[MAXN];
int lastOccurrence[3];

inline int getIdx(char c) {
	return c == 'L' ? 0 : (c == 'R' ? 1 : 2);
}

inline char toChar(bool idx) {
	return idx ? 'R' : 'L';
}

inline bool isMovDown(char c) {
	return c == 'L' or c == 'R';
}

bool dontHaveMovUp() {
	int i, n = T.size();
	bool res = true;

	for (i = 0; i < n; ++i) {
		if (!isMovDown(T[i])) {
			res = false;
		} else {
			direction = getIdx(T[i]);

			if (! res) {
				return res;
				break;
			}
		}
	}

	return res;
}

inline int modMult(int a, int b) {
	return ((a % MOD) * (b % MOD)) % MOD;
}

inline int modPositive(int n) {
	return ((n % MOD) + MOD) % MOD;
}

inline int modSub(int a, int b) {
	return ((a % MOD) - (b % MOD)) % MOD;
}

inline int modSum(int a, int b) {
	return ((a % MOD) + (b % MOD)) % MOD;
}

int countDistinctSubsequences() {
	int i, n, charIdx;

	n = T.size(), DP[0] = 1;

	for (i = 1; i <= n; ++i) {
		DP[i] = modMult(2, DP[i - 1]);
		charIdx = getIdx(T[i - 1]);

		if (lastOccurrence[charIdx] > 0) {
			DP[i] = modPositive(modSub(DP[i], DP[lastOccurrence[charIdx] - 1]));
		}

		lastOccurrence[charIdx] = i;
	}

	return DP[n];
}

void getFinalDirections() {
	int i, n = S.size();

	for (i = 0; i < n; ++i) {
		if (isMovDown(S[i])) {
			ParentDirections.push(getIdx(S[i]) ^ 1);
		} else if (! ParentDirections.empty()) {
			ParentDirections.pop();
		}
	}

	stackbl tmp(ParentDirections);

	while (!tmp.empty()) {
		ChildrenDirections.PB(tmp.top() ^ 1);
		tmp.pop();
	}

	reverse(ALL(ChildrenDirections));
}

void findMovsLater() {
	int i, n = T.size(), movs = 0;

	for (i = n - 1; i >= 0; --i) {
		if (isMovDown(T[i])) {
			++movs;
		} else {
			MovsLater.push(movs);
		}
	}

	MovsLater.push(movs);
}

int countDistinctNodes() {
	int movs, res = 0, i = 0, parentDirection;

	while ((! MovsLater.empty()) and (! ParentDirections.empty())) {
		movs = MovsLater.top();
		MovsLater.pop();

		if (i == 0) {
			res = modSum(res, modSum(movs, 1));
		} else {
			parentDirection = ParentDirections.top();
			ParentDirections.pop();

			if (parentDirection == direction) {
				res = modSum(res, movs);
			}

			res = modSum(res, 1);
		}

		++i;
	}

	return res;
}

typedef pair<int, int> Pair;
typedef pair<Pair, Pair> Tern;

vector<Tern> BT;
vector<string> Subsequences;
set<int> ans;

int createNode(int val) {
	int idx = BT.size();
	BT.PB(MP(MP(val, idx), MP(INF, INF)));
	return idx;
}

int generateTree(int node, int level) {
	if (level >= ChildrenDirections.size()) {
		return node;
	}

	bool direction = ChildrenDirections[level];

	if (direction == L) {
		int leftIdx = createNode(level + 1);
		BT[leftIdx].PARENT = node;
		BT[node].LEFT = leftIdx;
		return generateTree(leftIdx, level + 1);
	}  else {
		int rightIdx = createNode(level + 1);
		BT[rightIdx].PARENT = node;
		BT[node].RIGHT = rightIdx;
		return generateTree(rightIdx, level + 1);
	}
}

void printTree() {
	int i, n = BT.size();

	cout << "Tree: " << endl;
	for (i = 0; i < n; ++i)
		cout << setw(2) << BT[i].NODE << " ";
	cout << endl;
	for (i = 0; i < n; ++i)
		cout << setw(2) << BT[i].PARENT << " ";
	cout << endl;
	for (i = 0; i < n; ++i)
		cout << setw(2) << BT[i].LEFT << " ";
	cout << endl;
	for (i = 0; i < n; ++i)
		cout << setw(2) << BT[i].RIGHT << " ";
	cout << endl;
}

void generateAllSubsequences() {
	int i, j, n = T.size(), iter = 0;
	string s;
	set<string> heap;

	//cout << "All Subs: " << endl;
	for (i = 0; i < (1 << n); ++i) {
			s = "";

			for (j = 0; j < n; ++j) {
				if ((i & (1 << j)) > 0) {
					s += T[j];
				}
			}

			heap.insert(s);
			//cout << ">" << s << endl;
	}
	//cout << endl;

	for (set<string>::iterator it = heap.begin(); it != heap.end(); ++it) {
		Subsequences.PB((*it));
	}
}

void travel(int node, int subsequenceIdx, int level) {
	if (node != INF) {
		ans.insert(node);
	}

	if (level >= Subsequences[subsequenceIdx].size()) {
		return;
	}

	char c = Subsequences[subsequenceIdx][level];
	//cout << c << " ";

	if (c == 'U') {
		travel(BT[node].PARENT, subsequenceIdx, level + 1);
	} else if (c == 'L') {
		if (BT[node].LEFT == INF) {
			int leftIdx = createNode(BT.size());
			BT[leftIdx].PARENT = node;
			BT[node].LEFT = leftIdx;
		}

		travel(BT[node].LEFT, subsequenceIdx, level + 1);
	} else {
		if (BT[node].RIGHT == INF) {
			int rightIdx = createNode(BT.size());
			BT[rightIdx].PARENT = node;
			BT[node].RIGHT = rightIdx;
		}

		travel(BT[node].RIGHT, subsequenceIdx, level + 1);
	}
}

void findDistinctNodes(int currentNode) {
	int i, n = Subsequences.size();

	for (i = 0; i < n; ++i) {
		//cout << ">";
		travel(currentNode, i, 0);
		//cout << endl;
	}
}

int main() {
	optimize_ios

	cin >> S >> T;

	getFinalDirections();

	if (T.size() <= 20) {
		int root = createNode(0);
		int currentNode = generateTree(root, 0);
		//dd(currentNode);
		//printTree();
		generateAllSubsequences();
		findDistinctNodes(currentNode);
		/*printTree();
		cout << "Different Nodes: " << endl;
		for (set<int>::iterator it = ans.begin(); it != ans.end(); ++it) {
			cout << (*it) << " ";
		}
		cout << endl;*/
		cout << ans.size() << '\n';
	} else if (dontHaveMovUp()) {
		cout << countDistinctSubsequences() << '\n';
	} else {
		findMovsLater();
		cout << countDistinctNodes() << '\n';
	}
	return 0;
}
<commit_msg>omegaUp - TeamSkynet-Training-01 - Árbol Binario de Turing - Subtask 5 of 5 - AC<commit_after>#include <bits/stdc++.h>
#define optimize_ios ios_base::sync_with_stdio(0);cin.tie(0);
#define dd(x) cout << #x << ": " << x << endl;
#define PB push_back
#define MP make_pair
#define X first
#define Y second
#define ALL(x) x.begin(), x.end()
#define L 0
#define R 1
#define INF -1
#define MOD 21092013
using namespace std;
typedef stack<short> stacki;
typedef pair<int, int> Pair;
typedef pair<int, Pair> Tern;

string S, T;
stacki ParentDirections;
vector<int> DP;
int last[3];
int ans;

inline int modPositive(int n) {
	return ((n % MOD) + MOD) % MOD;
}

inline int modSub(int a, int b) {
	return modPositive(((a % MOD) - (b % MOD)) % MOD);
}

inline int modSum(int a, int b) {
	return ((a % MOD) + (b % MOD)) % MOD;
}

inline int modMult(int a, int b) {
	return ((a % MOD) * (b % MOD)) % MOD;
}

inline short getIdx(char c) {
	return (c == 'L' ? 0 : ((c == 'R') ? 1 : 2));
}

inline bool isUp(char c) {
	return c == 'U';
}

void getFinalDirections() {
	int i, n = S.size();

	for (i = 0; i < n; ++i) {
		if (! isUp(S[i])) {
			ParentDirections.push(getIdx(S[i]) ^ 1);
		} else if (! ParentDirections.empty()) {
			ParentDirections.pop();
		}
	}
}

void calculate() {
	int n, i, j, idx, lastLIdx = INF, lastRIdx = INF, subsequencesCount, dpIdx;
	vector<Tern> uIdx;

	DP.PB(1);

	for (i = T.size() - 1, j = 1; i >= 0; --i) {
		idx = getIdx(T[i]);

		if (! isUp(T[i])) {
			DP.PB(modMult(2, DP[j - 1]));

			if (last[idx] > 0) {
				DP[j] = modSub(DP[j], DP[last[idx] - 1]);
			}

			if (idx == L) {
				lastLIdx = j;
			} else {
				lastRIdx = j;
			}

			last[idx] = j++;
		} else {
			uIdx.PB(MP(j - 1, MP(lastLIdx, lastRIdx)));
		}
	}

	ans = modSum(ans, DP[j - 1]);

	for (i = uIdx.size() - 1; i >= 0 and ! ParentDirections.empty(); --i) {
		idx = ParentDirections.top(); ParentDirections.pop();
		subsequencesCount = DP[uIdx[i].X];
		dpIdx = idx == R ? uIdx[i].Y.X : uIdx[i].Y.Y;

		if (dpIdx == INF) {
			ans = modSum(ans, subsequencesCount);
		} else {
			ans = modSum(ans, modSub(subsequencesCount, DP[dpIdx - 1]));
		}
	}
}

int main() {
	optimize_ios

	cin >> S >> T;

	getFinalDirections();
	calculate();

	cout << ans << '\n';
	return 0;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "oox/drawingml/textparagraphpropertiescontext.hxx"

#include <com/sun/star/text/WritingMode.hpp>
#include <com/sun/star/awt/FontDescriptor.hpp>

#include "oox/drawingml/colorchoicecontext.hxx"
#include "oox/drawingml/textcharacterpropertiescontext.hxx"
#include "oox/drawingml/fillproperties.hxx"
#include "oox/helper/attributelist.hxx"
#include "textspacingcontext.hxx"
#include "texttabstoplistcontext.hxx"

using ::rtl::OUString;
using namespace ::oox::core;
using ::com::sun::star::awt::FontDescriptor;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::com::sun::star::style;
using namespace ::com::sun::star::text;

namespace oox { namespace drawingml {

// CT_TextParagraphProperties
TextParagraphPropertiesContext::TextParagraphPropertiesContext( ContextHandler& rParent,
                                                                const Reference< XFastAttributeList >& xAttribs,
                                                                TextParagraphProperties& rTextParagraphProperties )
: ContextHandler( rParent )
, mrTextParagraphProperties( rTextParagraphProperties )
, mrSpaceBefore( rTextParagraphProperties.getParaTopMargin() )
, mrSpaceAfter( rTextParagraphProperties.getParaBottomMargin() )
, mrBulletList( rTextParagraphProperties.getBulletList() )
{
    OUString sValue;
    AttributeList attribs( xAttribs );

    PropertyMap& rPropertyMap( mrTextParagraphProperties.getTextParagraphPropertyMap() );

    // ST_TextAlignType
    if ( xAttribs->hasAttribute( XML_algn ) )
    {
        sal_Int32 nAlign = xAttribs->getOptionalValueToken( XML_algn, XML_l );
        rPropertyMap[ PROP_ParaAdjust ] <<= GetParaAdjust( nAlign );
    }
//  OSL_TRACE( "OOX: para adjust %d", GetParaAdjust( nAlign ));
    // TODO see to do the same with RubyAdjust

    // ST_Coordinate32
//  sValue = xAttribs->getOptionalValue( XML_defTabSz );    SJ: we need to be able to set the default tab size for each text object,
//                                                          this is possible at the moment only for the whole document.
//  sal_Int32 nDefTabSize = ( sValue.getLength() == 0 ? 0 : GetCoordinate(  sValue ) );
    // TODO

//  bool bEaLineBrk = attribs.getBool( XML_eaLnBrk, true );
    if ( xAttribs->hasAttribute( XML_latinLnBrk ) )
    {
        bool bLatinLineBrk = attribs.getBool( XML_latinLnBrk, true );
        rPropertyMap[ PROP_ParaIsHyphenation ] <<= bLatinLineBrk;
    }
    // TODO see what to do with Asian hyphenation

    // ST_TextFontAlignType
    // TODO
//  sal_Int32 nFontAlign = xAttribs->getOptionalValueToken( XML_fontAlgn, XML_base );

    if ( xAttribs->hasAttribute( XML_hangingPunct ) )
    {
        bool bHangingPunct = attribs.getBool( XML_hangingPunct, false );
        rPropertyMap[ PROP_ParaIsHangingPunctuation ] <<= bHangingPunct;
    }

  // ST_Coordinate
    if ( xAttribs->hasAttribute( XML_indent ) )
    {
        sValue = xAttribs->getOptionalValue( XML_indent );
        mrTextParagraphProperties.getFirstLineIndentation() = boost::optional< sal_Int32 >( sValue.isEmpty() ? 0 : GetCoordinate( sValue ) );
    }

  // ST_TextIndentLevelType
    // -1 is an invalid value and denote the lack of level
    sal_Int32 nLevel = attribs.getInteger( XML_lvl, 0 );
    if( nLevel > 8 || nLevel < 0 )
    {
        nLevel = 0;
    }

    mrTextParagraphProperties.setLevel( static_cast< sal_Int16 >( nLevel ) );

    char name[] = "Outline X";
    name[8] = static_cast<char>( '1' + nLevel );
    const OUString sStyleNameValue( rtl::OUString::createFromAscii( name ) );
    mrBulletList.setStyleName( sStyleNameValue );

    // ST_TextMargin
    // ParaLeftMargin
    if ( xAttribs->hasAttribute( XML_marL ) )
    {
        sValue = xAttribs->getOptionalValue( XML_marL );
        mrTextParagraphProperties.getParaLeftMargin() = boost::optional< sal_Int32 >( sValue.isEmpty() ? 0 : GetCoordinate( sValue ) );
    }

    // ParaRightMargin
    if ( xAttribs->hasAttribute( XML_marR ) )
    {
        sValue = xAttribs->getOptionalValue( XML_marR );
        sal_Int32 nMarR  = sValue.isEmpty() ? 0 : GetCoordinate( sValue ) ;
        rPropertyMap[ PROP_ParaRightMargin ] <<= nMarR;
    }

    if ( xAttribs->hasAttribute( XML_rtl ) )
    {
        bool bRtl = attribs.getBool( XML_rtl, false );
        rPropertyMap[ PROP_TextWritingMode ] <<= ( bRtl ? WritingMode_RL_TB : WritingMode_LR_TB );
    }
}

TextParagraphPropertiesContext::~TextParagraphPropertiesContext()
{
    PropertyMap& rPropertyMap( mrTextParagraphProperties.getTextParagraphPropertyMap() );
    if ( maLineSpacing.bHasValue )
        rPropertyMap[ PROP_ParaLineSpacing ] <<= maLineSpacing.toLineSpacing();

    ::std::list< TabStop >::size_type nTabCount = maTabList.size();
    if( nTabCount != 0 )
    {
        Sequence< TabStop > aSeq( nTabCount );
        TabStop * aArray = aSeq.getArray();
        OSL_ENSURE( aArray != NULL, "sequence array is NULL" );
        ::std::copy( maTabList.begin(), maTabList.end(), aArray );
        rPropertyMap[ PROP_ParaTabStops ] <<= aSeq;
    }

    if ( mxBlipProps.get() && mxBlipProps->mxGraphic.is() )
        mrBulletList.setGraphic( mxBlipProps->mxGraphic );

    if( mrBulletList.is() )
        rPropertyMap[ PROP_IsNumbering ] <<= sal_True;
    sal_Int16 nLevel = mrTextParagraphProperties.getLevel();
    rPropertyMap[ PROP_NumberingLevel ] <<= nLevel;
    rPropertyMap[ PROP_NumberingIsNumber ] <<= sal_True;
}

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

void TextParagraphPropertiesContext::endFastElement( sal_Int32 ) throw (SAXException, RuntimeException)
{
}

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

Reference< XFastContextHandler > TextParagraphPropertiesContext::createFastChildContext( sal_Int32 aElementToken, const Reference< XFastAttributeList >& rXAttributes ) throw (SAXException, RuntimeException)
{
    AttributeList aAttribs( rXAttributes );
    Reference< XFastContextHandler > xRet;
    switch( aElementToken )
    {
        case A_TOKEN( lnSpc ):          // CT_TextSpacing
            xRet.set( new TextSpacingContext( *this, maLineSpacing ) );
            break;
        case A_TOKEN( spcBef ):         // CT_TextSpacing
            xRet.set( new TextSpacingContext( *this, mrSpaceBefore ) );
            break;
        case A_TOKEN( spcAft ):         // CT_TextSpacing
            xRet.set( new TextSpacingContext( *this, mrSpaceAfter ) );
            break;

        // EG_TextBulletColor
        case A_TOKEN( buClrTx ):        // CT_TextBulletColorFollowText ???
            mrBulletList.mbBulletColorFollowText <<= sal_True;
            break;
        case A_TOKEN( buClr ):          // CT_Color
            xRet.set( new ColorContext( *this, *mrBulletList.maBulletColorPtr ) );
            break;

        // EG_TextBulletSize
        case A_TOKEN( buSzTx ):         // CT_TextBulletSizeFollowText
            mrBulletList.setBulletSize(100);
            break;
        case A_TOKEN( buSzPct ):        // CT_TextBulletSizePercent
            mrBulletList.setBulletSize( static_cast<sal_Int16>( GetPercent( rXAttributes->getOptionalValue( XML_val ) ) / 1000 ) );
            break;
        case A_TOKEN( buSzPts ):        // CT_TextBulletSizePoint
            mrBulletList.setBulletSize(0);
            mrBulletList.setFontSize( static_cast<sal_Int16>(GetTextSize( rXAttributes->getOptionalValue( XML_val ) ) ) );
            break;

        // EG_TextBulletTypeface
        case A_TOKEN( buFontTx ):       // CT_TextBulletTypefaceFollowText
            mrBulletList.mbBulletFontFollowText <<= sal_True;
            break;
        case A_TOKEN( buFont ):         // CT_TextFont
            mrBulletList.maBulletFont.setAttributes( aAttribs );
            break;

        // EG_TextBullet
        case A_TOKEN( buNone ):         // CT_TextNoBullet
            mrBulletList.setNone();
            break;
        case A_TOKEN( buAutoNum ):      // CT_TextAutonumberBullet
        {
            AttributeList attribs( rXAttributes );
            try {
                sal_Int32 nType = rXAttributes->getValueToken( XML_type );
                sal_Int32 nStartAt = attribs.getInteger( XML_startAt, 1 );
                if( nStartAt > 32767 )
                {
                    nStartAt = 32767;
                }
                else if( nStartAt < 1 )
                {
                    nStartAt = 1;
                }
                mrBulletList.setStartAt( nStartAt );
                mrBulletList.setType( nType );
            }
            catch(SAXException& /* e */ )
            {
                OSL_TRACE("OOX: SAXException in XML_buAutoNum");
            }
            break;
        }
        case A_TOKEN( buChar ):         // CT_TextCharBullet
            try {
                mrBulletList.setBulletChar( rXAttributes->getValue( XML_char ) );
            }
            catch(SAXException& /* e */)
            {
                OSL_TRACE("OOX: SAXException in XML_buChar");
            }
            break;
        case A_TOKEN( buBlip ):         // CT_TextBlipBullet
            {
                mxBlipProps.reset( new BlipFillProperties );
                xRet.set( new BlipFillContext( *this, rXAttributes, *mxBlipProps ) );
            }
            break;

        case A_TOKEN( tabLst ):         // CT_TextTabStopList
            xRet.set( new TextTabStopListContext( *this, maTabList ) );
            break;
        case A_TOKEN( defRPr ):         // CT_TextCharacterProperties
            xRet.set( new TextCharacterPropertiesContext( *this, rXAttributes, mrTextParagraphProperties.getTextCharacterProperties() ) );
            break;
    }
    if ( !xRet.is() )
        xRet.set( this );
    return xRet;
}

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

} }

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>n734734: Line Spacing is used from previous values.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "oox/drawingml/textparagraphpropertiescontext.hxx"

#include <com/sun/star/text/WritingMode.hpp>
#include <com/sun/star/awt/FontDescriptor.hpp>

#include "oox/drawingml/colorchoicecontext.hxx"
#include "oox/drawingml/textcharacterpropertiescontext.hxx"
#include "oox/drawingml/fillproperties.hxx"
#include "oox/helper/attributelist.hxx"
#include "textspacingcontext.hxx"
#include "texttabstoplistcontext.hxx"

using ::rtl::OUString;
using namespace ::oox::core;
using ::com::sun::star::awt::FontDescriptor;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::com::sun::star::style;
using namespace ::com::sun::star::text;

namespace oox { namespace drawingml {

// CT_TextParagraphProperties
TextParagraphPropertiesContext::TextParagraphPropertiesContext( ContextHandler& rParent,
                                                                const Reference< XFastAttributeList >& xAttribs,
                                                                TextParagraphProperties& rTextParagraphProperties )
: ContextHandler( rParent )
, mrTextParagraphProperties( rTextParagraphProperties )
, mrSpaceBefore( rTextParagraphProperties.getParaTopMargin() )
, mrSpaceAfter( rTextParagraphProperties.getParaBottomMargin() )
, mrBulletList( rTextParagraphProperties.getBulletList() )
{
    OUString sValue;
    AttributeList attribs( xAttribs );

    PropertyMap& rPropertyMap( mrTextParagraphProperties.getTextParagraphPropertyMap() );

    // ST_TextAlignType
    if ( xAttribs->hasAttribute( XML_algn ) )
    {
        sal_Int32 nAlign = xAttribs->getOptionalValueToken( XML_algn, XML_l );
        rPropertyMap[ PROP_ParaAdjust ] <<= GetParaAdjust( nAlign );
    }
//  OSL_TRACE( "OOX: para adjust %d", GetParaAdjust( nAlign ));
    // TODO see to do the same with RubyAdjust

    // ST_Coordinate32
//  sValue = xAttribs->getOptionalValue( XML_defTabSz );    SJ: we need to be able to set the default tab size for each text object,
//                                                          this is possible at the moment only for the whole document.
//  sal_Int32 nDefTabSize = ( sValue.getLength() == 0 ? 0 : GetCoordinate(  sValue ) );
    // TODO

//  bool bEaLineBrk = attribs.getBool( XML_eaLnBrk, true );
    if ( xAttribs->hasAttribute( XML_latinLnBrk ) )
    {
        bool bLatinLineBrk = attribs.getBool( XML_latinLnBrk, true );
        rPropertyMap[ PROP_ParaIsHyphenation ] <<= bLatinLineBrk;
    }
    // TODO see what to do with Asian hyphenation

    // ST_TextFontAlignType
    // TODO
//  sal_Int32 nFontAlign = xAttribs->getOptionalValueToken( XML_fontAlgn, XML_base );

    if ( xAttribs->hasAttribute( XML_hangingPunct ) )
    {
        bool bHangingPunct = attribs.getBool( XML_hangingPunct, false );
        rPropertyMap[ PROP_ParaIsHangingPunctuation ] <<= bHangingPunct;
    }

  // ST_Coordinate
    if ( xAttribs->hasAttribute( XML_indent ) )
    {
        sValue = xAttribs->getOptionalValue( XML_indent );
        mrTextParagraphProperties.getFirstLineIndentation() = boost::optional< sal_Int32 >( sValue.isEmpty() ? 0 : GetCoordinate( sValue ) );
    }

  // ST_TextIndentLevelType
    // -1 is an invalid value and denote the lack of level
    sal_Int32 nLevel = attribs.getInteger( XML_lvl, 0 );
    if( nLevel > 8 || nLevel < 0 )
    {
        nLevel = 0;
    }

    mrTextParagraphProperties.setLevel( static_cast< sal_Int16 >( nLevel ) );

    char name[] = "Outline X";
    name[8] = static_cast<char>( '1' + nLevel );
    const OUString sStyleNameValue( rtl::OUString::createFromAscii( name ) );
    mrBulletList.setStyleName( sStyleNameValue );

    // ST_TextMargin
    // ParaLeftMargin
    if ( xAttribs->hasAttribute( XML_marL ) )
    {
        sValue = xAttribs->getOptionalValue( XML_marL );
        mrTextParagraphProperties.getParaLeftMargin() = boost::optional< sal_Int32 >( sValue.isEmpty() ? 0 : GetCoordinate( sValue ) );
    }

    // ParaRightMargin
    if ( xAttribs->hasAttribute( XML_marR ) )
    {
        sValue = xAttribs->getOptionalValue( XML_marR );
        sal_Int32 nMarR  = sValue.isEmpty() ? 0 : GetCoordinate( sValue ) ;
        rPropertyMap[ PROP_ParaRightMargin ] <<= nMarR;
    }

    if ( xAttribs->hasAttribute( XML_rtl ) )
    {
        bool bRtl = attribs.getBool( XML_rtl, false );
        rPropertyMap[ PROP_TextWritingMode ] <<= ( bRtl ? WritingMode_RL_TB : WritingMode_LR_TB );
    }
}

TextParagraphPropertiesContext::~TextParagraphPropertiesContext()
{
    PropertyMap& rPropertyMap( mrTextParagraphProperties.getTextParagraphPropertyMap() );
    if ( maLineSpacing.bHasValue )
        rPropertyMap[ PROP_ParaLineSpacing ] <<= maLineSpacing.toLineSpacing();
    else
        rPropertyMap[ PROP_ParaLineSpacing ] <<= ::com::sun::star::style::LineSpacing( ::com::sun::star::style::LineSpacingMode::PROP, 100 );

    ::std::list< TabStop >::size_type nTabCount = maTabList.size();
    if( nTabCount != 0 )
    {
        Sequence< TabStop > aSeq( nTabCount );
        TabStop * aArray = aSeq.getArray();
        OSL_ENSURE( aArray != NULL, "sequence array is NULL" );
        ::std::copy( maTabList.begin(), maTabList.end(), aArray );
        rPropertyMap[ PROP_ParaTabStops ] <<= aSeq;
    }

    if ( mxBlipProps.get() && mxBlipProps->mxGraphic.is() )
        mrBulletList.setGraphic( mxBlipProps->mxGraphic );

    if( mrBulletList.is() )
        rPropertyMap[ PROP_IsNumbering ] <<= sal_True;
    sal_Int16 nLevel = mrTextParagraphProperties.getLevel();
    rPropertyMap[ PROP_NumberingLevel ] <<= nLevel;
    rPropertyMap[ PROP_NumberingIsNumber ] <<= sal_True;
}

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

void TextParagraphPropertiesContext::endFastElement( sal_Int32 ) throw (SAXException, RuntimeException)
{
}

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

Reference< XFastContextHandler > TextParagraphPropertiesContext::createFastChildContext( sal_Int32 aElementToken, const Reference< XFastAttributeList >& rXAttributes ) throw (SAXException, RuntimeException)
{
    AttributeList aAttribs( rXAttributes );
    Reference< XFastContextHandler > xRet;
    switch( aElementToken )
    {
        case A_TOKEN( lnSpc ):          // CT_TextSpacing
            xRet.set( new TextSpacingContext( *this, maLineSpacing ) );
            break;
        case A_TOKEN( spcBef ):         // CT_TextSpacing
            xRet.set( new TextSpacingContext( *this, mrSpaceBefore ) );
            break;
        case A_TOKEN( spcAft ):         // CT_TextSpacing
            xRet.set( new TextSpacingContext( *this, mrSpaceAfter ) );
            break;

        // EG_TextBulletColor
        case A_TOKEN( buClrTx ):        // CT_TextBulletColorFollowText ???
            mrBulletList.mbBulletColorFollowText <<= sal_True;
            break;
        case A_TOKEN( buClr ):          // CT_Color
            xRet.set( new ColorContext( *this, *mrBulletList.maBulletColorPtr ) );
            break;

        // EG_TextBulletSize
        case A_TOKEN( buSzTx ):         // CT_TextBulletSizeFollowText
            mrBulletList.setBulletSize(100);
            break;
        case A_TOKEN( buSzPct ):        // CT_TextBulletSizePercent
            mrBulletList.setBulletSize( static_cast<sal_Int16>( GetPercent( rXAttributes->getOptionalValue( XML_val ) ) / 1000 ) );
            break;
        case A_TOKEN( buSzPts ):        // CT_TextBulletSizePoint
            mrBulletList.setBulletSize(0);
            mrBulletList.setFontSize( static_cast<sal_Int16>(GetTextSize( rXAttributes->getOptionalValue( XML_val ) ) ) );
            break;

        // EG_TextBulletTypeface
        case A_TOKEN( buFontTx ):       // CT_TextBulletTypefaceFollowText
            mrBulletList.mbBulletFontFollowText <<= sal_True;
            break;
        case A_TOKEN( buFont ):         // CT_TextFont
            mrBulletList.maBulletFont.setAttributes( aAttribs );
            break;

        // EG_TextBullet
        case A_TOKEN( buNone ):         // CT_TextNoBullet
            mrBulletList.setNone();
            break;
        case A_TOKEN( buAutoNum ):      // CT_TextAutonumberBullet
        {
            AttributeList attribs( rXAttributes );
            try {
                sal_Int32 nType = rXAttributes->getValueToken( XML_type );
                sal_Int32 nStartAt = attribs.getInteger( XML_startAt, 1 );
                if( nStartAt > 32767 )
                {
                    nStartAt = 32767;
                }
                else if( nStartAt < 1 )
                {
                    nStartAt = 1;
                }
                mrBulletList.setStartAt( nStartAt );
                mrBulletList.setType( nType );
            }
            catch(SAXException& /* e */ )
            {
                OSL_TRACE("OOX: SAXException in XML_buAutoNum");
            }
            break;
        }
        case A_TOKEN( buChar ):         // CT_TextCharBullet
            try {
                mrBulletList.setBulletChar( rXAttributes->getValue( XML_char ) );
            }
            catch(SAXException& /* e */)
            {
                OSL_TRACE("OOX: SAXException in XML_buChar");
            }
            break;
        case A_TOKEN( buBlip ):         // CT_TextBlipBullet
            {
                mxBlipProps.reset( new BlipFillProperties );
                xRet.set( new BlipFillContext( *this, rXAttributes, *mxBlipProps ) );
            }
            break;

        case A_TOKEN( tabLst ):         // CT_TextTabStopList
            xRet.set( new TextTabStopListContext( *this, maTabList ) );
            break;
        case A_TOKEN( defRPr ):         // CT_TextCharacterProperties
            xRet.set( new TextCharacterPropertiesContext( *this, rXAttributes, mrTextParagraphProperties.getTextCharacterProperties() ) );
            break;
    }
    if ( !xRet.is() )
        xRet.set( this );
    return xRet;
}

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

} }

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before><commit_msg>Minor comment fix.<commit_after><|endoftext|>


<commit_before>
#include "image.h"
#include "pnm.h"
#include "ifs.h"
#include "vec3.h"
#include "camera.h"
#include "quaternion.h"

#include <vector>
#include <string>

#include <cmath>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

typedef IFS::IFS< Vec3d > myIFS;

typedef MathVector<unsigned char,3> RGB;    // RGB color value
#define PI 3.141592653589793238462643

// Image Projection allows to rayintersect with an
// (panoramic) image taken from a known pose
class ImageProjection
{
public:
    virtual Vec3d getPosition() = 0;
    virtual RGB   getColorProjection(const Vec3d &pos) const = 0;
};

class SphericalPanoramaImageProjection : public ImageProjection
{
private:
    Camera<double> camera;
    Image pano;

public:
    Vec2d azimuthRange;
    Vec2d elevationRange;

    SphericalPanoramaImageProjection()
        : azimuthRange(0, 2 * PI), elevationRange(-PI/2,PI/2)
    {
    }

    inline void setPanoramicImage(const Image &pi) { pano = pi; }
    inline void setCenter(const Vec3d &center)     { camera.setPosition(center); }
    inline void setPose(const Vec3d &right, const Vec3d &up, const Vec3d &front)
    {
        camera.setOrientation(right, up, front);
    }

    inline const Image & img()  { return pano; }

    inline bool isValid() const { return pano.isValid(); }
    inline Vec3d getPosition()  { return camera.getPosition(); }

    inline bool applyRotation(Quaterniond &quat)
    {
        camera.applyRotation(quat);
        return true;
    }

    RGB   getColorProjection(const Vec3d &pos) const
    {
        // get vector from camera center to position
        Vec3d rayWorld = pos - camera.getPosition();

        // transform to camera orientation
        Vec3d ray = camera.world2cam() * rayWorld;

        // normalize vector to get the intersection on the unit sphere
        ray.normalize();

        // pano-x = azimuth   = phi   = atan2(y,x) normalized to [0,1]
        // pano-y = elevation = theta = arccos(z/sqrt(x^2+y^2+z^2)) normalized to [-1,1], norm can be neglected
        //                                         since (x,y,z) is already normalized
        // physical notation, theta=inclination/elevation=pano-x ,phi = azimuth = pano-y
        Vec3d spherical = cart2spher(ray);

        // get relative value to  bounds
        const double tx = (spherical[0] - azimuthRange[0]) / (azimuthRange[1] - azimuthRange[0]);
        const double ty = (spherical[1] - elevationRange[0]) / (elevationRange[1] - elevationRange[0]);

        // pano lookup, nearest neighbor for now.. TODO: interpolation
        RGB pixel(0,0,0);
        if (tx >= 0.0 && tx <= 1.0 && ty >= 0.0 && ty <= 1.0)
        {
            pixel[0] = pano(tx*pano.width(), ty*pano.height(), 0);
            pixel[1] = pano(tx*pano.width(), ty*pano.height(), 1);
            pixel[2] = pano(tx*pano.width(), ty*pano.height(), 2);
        }
        return pixel;
    }

    // COORDINATE SYSTEM CONVERSIONS

    // cartesian coordinates: Vec3 [ x, y, z ]
    // spherical coordinates: Vec3 [ azimuth , inclination , radius ]
    Vec3d spher2cart(const Vec3d &spc) const
    {
        return Vec3d(
            spc[2] * sin(spc[1]) * cos(spc[0]),
            spc[2] * sin(spc[1]) * sin(spc[0]),
            spc[2] * cos(spc[1])
        );
    }

    // cartesian to spherical coordinates
    Vec3d cart2spher(const Vec3d &cart) const
    {
        double radius    = cart.length();
        double inclination = acos(cart[2] / radius);
        double azimuth   = atan2(cart[1], cart[0]);
        if (azimuth < 0) azimuth += 2.0*PI;

        assert(inclination >= 0.0 && inclination <= PI);
        assert(azimuth >= 0.0 && azimuth <= 2.0*PI);

        return Vec3d(azimuth, inclination, radius);

    }

    // export to textured sphere
    myIFS exportToIFS(const double r = 1.0, const double numpts = 10)
    {
        myIFS result;
        result.useTextureCoordinates = true;

        const double inclinationStep = (PI / numpts);
        const double azimuthStep = (2.0*PI / numpts);

        const Vec3d delta1(azimuthStep, 0, 0);
        const Vec3d delta2(azimuthStep, inclinationStep, 0);
        const Vec3d delta3(0, inclinationStep, 0);

        const Vec2f txd1(azimuthStep, 0);
        const Vec2f txd2(azimuthStep, inclinationStep);
        const Vec2f txd3(0, inclinationStep);
        const Vec2f txnorm(1.0/(2.0*PI), 1.0/PI);

        // create points on a sphere
        for (double e = 0; e < PI; e += inclinationStep)
        {
            for (double a = 0; a < 2 * PI; a += azimuthStep)
            {
                const Vec3d spherical(a, e, r);
                const Vec2f texcoord(a, e);

                std::set<myIFS::IFSINDEX> face;
                myIFS::IFSFACE ifsface;

                auto insertVertex = [&face, &ifsface](myIFS::IFSINDEX i)
                {
                    face.insert(i);
                    ifsface.push_back(i);
                };

                insertVertex(result.vertex2index(spher2cart(spherical), texcoord.elMul(txnorm)));
                insertVertex(result.vertex2index(spher2cart(spherical + delta1), (texcoord + txd1).elMul(txnorm)));
                insertVertex(result.vertex2index(spher2cart(spherical + delta2), (texcoord + txd2).elMul(txnorm)));
                insertVertex(result.vertex2index(spher2cart(spherical + delta3), (texcoord + txd3).elMul(txnorm)));
                // process only non-degenerated faces
                if (face.size() == 4)
                {
                    result.faces.push_back(ifsface);
                }
            }
        }

        return result;
    }
};

template< class T >
struct Quad3D
{
    T V[4];

    // vertices are given in CCW order
    Quad3D(const T &v0, const T &v1, const T &v2, const T &v3)
    {
        // we assume that the Z direction corresponds to the up direction in world space
        // therefore, order the points such that the points with maximum z coordinate
        // are given first, without changing the orientation
        typedef std::pair<double, unsigned int> vdat;

        std::vector < vdat > brak;
        const struct bcomp {
            inline bool operator() (const vdat &A, const vdat &B) const
            {
                return A.first < B.first;
            }
        } brakComp;

        brak.push_back(vdat(v0[2] + v1[2], 0));
        brak.push_back(vdat(v1[2] + v2[2], 1));
        brak.push_back(vdat(v2[2] + v3[2], 2));
        brak.push_back(vdat(v3[2] + v0[2], 3));
        std::sort(brak.begin(), brak.end(), brakComp);
        switch (brak[3].second)
        {
            case 0: V[0] = v0; V[1] = v1; V[2] = v2; V[3] = v3; break;
            case 1: V[0] = v1; V[1] = v2; V[2] = v3; V[3] = v0; break;
            case 2: V[0] = v2; V[1] = v3; V[2] = v0; V[3] = v1; break;
            case 3: V[0] = v3; V[1] = v0; V[2] = v1; V[3] = v2; break;
            default:
            std::abort();
        }
    }

    // resolution is <world units>/pixel
    Image performProjection(const ImageProjection& projection, double resolution) const
    {
#ifdef WRITE_POINTCLOUD_PER_FACE
        static int imagecounter = 0;
        std::ostringstream ss;
        ss << "cloud_" << imagecounter << ".xyz";
        std::ofstream pclfile(ss.str());
        ++imagecounter;
#endif

        // origin is left top
        T W  = V[1] - V[0];
        T H = V[3] - V[0];

        double width = W.length();
        double height = H.length();

        // get image space X and Y directional vectors in world coordinates
        T xdir = W; xdir.normalize();
        T ydir = H; ydir.normalize();

        Image img;
        img.initialize((int)(width/resolution)+1, (int)(height/resolution)+1, 24);

        for (int y = 0; y < img.height(); ++y)
        {
            const T vecy = H * (y / (double)img.height());
            for (int x = 0; x < img.width(); ++x)
            {
                // calculate position in world coordinates
                const T vecx = W * (x / (double)img.width());
                const T position = V[0] + vecx + vecy;

                // project color value
                RGB color = projection.getColorProjection(position);

                // write color value
                img(x, y, 0) = color[0];
                img(x, y, 1) = color[1];
                img(x, y, 2) = color[2];

#ifdef WRITE_POINTCLOUD_PER_FACE
                // write pointcloud file
                std::ostringstream pclpoint;
                pclpoint << position[0] << " " << position[1] << " " << position[2];
                pclpoint << " " << (int)color[0] << " " << (int)color[1] << " " << (int)color[2];
                pclfile << pclpoint.str() << std::endl;
#endif

            }
        }

        return img;
    }

};
typedef Quad3D<Vec3d> Quad3Dd;

// TODO: additional projection types?
//       - fisheye camera dewarping
//       - HomographyProjection from a planar image

int main(int ac, char* av[])
{
    SphericalPanoramaImageProjection projection;
    myIFS ingeometry;
    double resolution = 1.0;        // default: 1 mm/pixel

    std::cout << "OrthoGen orthographic image generator for DuraArk" << std::endl;

    try
    {
        po::options_description desc("commandline options");
        desc.add_options()
            ("help", "show this help message")
            ("im", po::value< std::string >(), "input panoramic image [.PNM]")
            ("ig", po::value< std::string >(), "input geometry [.OBJ]")
            ("res", po::value< double >(), "resolution [mm/pixel]")
            ("rot", po::value< std::vector<double> >()->multitoken(), "rotation quaternion [x,y,z,w]")
            ("elmin", po::value< double >(), "elevation min")
            ("elmax", po::value< double >(), "elevation max")
            ;

        po::variables_map vm;
        po::store(po::parse_command_line(ac, av, desc), vm);
        po::notify(vm);

        if (vm.count("help"))
        {
            std::cout << desc << "\n";
            return 0;
        }

        if (vm.count("im"))
        {
            // load pnm image
            projection.setPanoramicImage(PNM::loadPNM(vm["im"].as<std::string>()));
            if (!projection.img().isValid())
                std::cout << "Error: could not open "
                          << vm["im"].as<std::string>() << std::endl;
        }

        if (vm.count("ig"))
        {
            // load pnm image
            ingeometry = IFS::loadOBJ<myIFS>(vm["ig"].as<std::string>());
            if (!ingeometry.isValid())
                std::cout << "Error: could not open "
                          << vm["ig"].as<std::string>() << std::endl;
        }

        if (vm.count("res"))
        {
            resolution = vm["res"].as<double>();
        }

        if (vm.count("rot"))
        {
            std::vector<double> rot = vm["rot"].as<std::vector<double> >();
            if (rot.size() == 4)
            {
                Quaterniond quaternion(rot[0], rot[1], rot[2], rot[3]);
                std::cout << " applying quaternion [" << quaternion.a << ","
                    << quaternion.b << "," << quaternion.c << "," << quaternion.d
                    << "]" << std::endl;
                projection.applyRotation(quaternion);
            }
            else
            {
                std::cout << " --rot Error: quaternion is not composed of 4 values."
                          << std::endl;
            }
        }

        if (vm.count("elmin"))
        {
            projection.elevationRange[0] = vm["elmin"].as<double>();
        }
        if (vm.count("elmax"))
        {
            projection.elevationRange[1] = vm["elmax"].as<double>();
        }

    }
    catch(std::exception& e)
    {
        std::cerr << "error: " << e.what() << "\n";
        return 1;
    }

    if (projection.isValid() && ingeometry.isValid())
    {
        const Image &img = projection.img();
        //PNM::writePNM(img, "projection.pnm");
        std::cout << "input image is " << img.width() << " x " << img.height() << " pixels." << std::endl;
        std::cout << "input geometry consists of " << ingeometry.vertices.size() << " vertices and " << ingeometry.faces.size() << " faces." << std::endl;
        std::cout << "using a resolution of " << resolution << "mm/pixel" << std::endl;

        // PROCESS OUTPUT
        myIFS sphere = projection.exportToIFS(1000.0);
        IFS::exportOBJ(sphere, "sphere.obj");

        // TODO:
        // - input E57 image to read in pose (position / orientation)
        // - model position and orientation of pano
        // for each face:
        //   for each pixel: perform ray intersection with pano
        //   write output image

        int faceid = 0;
        for (auto const &face : ingeometry.faces)
        {
            if (face.size() == 4)
            {
                // create quad in 3D
                Quad3Dd quad(ingeometry.vertices[face[0]],
                             ingeometry.vertices[face[1]],
                             ingeometry.vertices[face[2]],
                             ingeometry.vertices[face[3]]);
                // raster quad
                Image orthophoto = quad.performProjection(projection, resolution);
                {
                    std::ostringstream oss;
                    oss << "ortho_" << faceid << ".pnm";
                    PNM::writePNM(orthophoto, oss.str());
                    std::cout << oss.str() << " : " << orthophoto.width() << "x" << orthophoto.height() << std::endl;
                }
            }
            else
            {
                std::cout << "[ERR]: non-quad face detected (" << face.size() << " vertices)." << std::endl;
            }
            ++faceid;
        }

        return 0;
    }

    std::cout << "--help for options." << std::endl;

}<commit_msg>fixes<commit_after>
#include "image.h"
#include "pnm.h"
#include "ifs.h"
#include "vec3.h"
#include "camera.h"
#include "quaternion.h"

#include <vector>
#include <string>

#include <cmath>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

typedef IFS::IFS< Vec3d > myIFS;

typedef MathVector<unsigned char,3> RGB;    // RGB color value
#define PI 3.141592653589793238462643

// Image Projection allows to rayintersect with an
// (panoramic) image taken from a known pose
class ImageProjection
{
public:
    virtual Vec3d getPosition() = 0;
    virtual RGB   getColorProjection(const Vec3d &pos) const = 0;
};

class SphericalPanoramaImageProjection : public ImageProjection
{
private:
    Camera<double> camera;
    Image pano;

public:
    Vec2d azimuthRange;
    Vec2d elevationRange;

    SphericalPanoramaImageProjection()
        : azimuthRange(0, 2 * PI), elevationRange(-PI/2,PI/2)
    {
    }

    inline void setPanoramicImage(const Image &pi) { pano = pi; }
    inline void setCenter(const Vec3d &center)     { camera.setPosition(center); }
    inline void setPose(const Vec3d &right, const Vec3d &up, const Vec3d &front)
    {
        camera.setOrientation(right, up, front);
    }

    inline const Image & img()  { return pano; }

    inline bool isValid() const { return pano.isValid(); }
    inline Vec3d getPosition()  { return camera.getPosition(); }

    inline bool applyRotation(Quaterniond &quat)
    {
        camera.applyRotation(quat);
        return true;
    }

    RGB   getColorProjection(const Vec3d &pos) const
    {
        // get vector from camera center to position
        Vec3d rayWorld = pos - camera.getPosition();

        // transform to camera orientation
        Vec3d ray = camera.world2cam() * rayWorld;

        // normalize vector to get the intersection on the unit sphere
        ray.normalize();

        // pano-x = azimuth   = phi   = atan2(y,x) normalized to [0,1]
        // pano-y = elevation = theta = arccos(z/sqrt(x^2+y^2+z^2)) normalized to [-1,1], norm can be neglected
        //                                         since (x,y,z) is already normalized
        // physical notation, theta=inclination/elevation=pano-x ,phi = azimuth = pano-y
        Vec3d spherical = cart2spher(ray);

        // get relative value to  bounds
        const double tx = (spherical[0] - azimuthRange[0]) / (azimuthRange[1] - azimuthRange[0]);
        const double ty = (spherical[1] - elevationRange[0]) / (elevationRange[1] - elevationRange[0]);

        // pano lookup, nearest neighbor for now.. TODO: interpolation
        RGB pixel(0,0,0);
        if (tx >= 0.0 && tx <= 1.0 && ty >= 0.0 && ty <= 1.0)
        {
            pixel[0] = pano(tx*pano.width(), ty*pano.height(), 0);
            pixel[1] = pano(tx*pano.width(), ty*pano.height(), 1);
            pixel[2] = pano(tx*pano.width(), ty*pano.height(), 2);
        }
        return pixel;
    }

    // COORDINATE SYSTEM CONVERSIONS

    // cartesian coordinates: Vec3 [ x, y, z ]
    // spherical coordinates: Vec3 [ azimuth , inclination , radius ]
    Vec3d spher2cart(const Vec3d &spc) const
    {
        return Vec3d(
            spc[2] * sin(spc[1]) * cos(spc[0]),
            spc[2] * sin(spc[1]) * sin(spc[0]),
            -spc[2] * cos(spc[1])
        );
    }

    // cartesian to spherical coordinates
    Vec3d cart2spher(const Vec3d &cart) const
    {
        double radius    = cart.length();
        double inclination = acos(cart[2] / radius);
        double azimuth   = atan2(cart[1], cart[0]);
        if (azimuth < 0) azimuth += 2.0*PI;

        assert(inclination >= 0.0 && inclination <= PI);
        assert(azimuth >= 0.0 && azimuth <= 2.0*PI);

        return Vec3d(azimuth, inclination, radius);

    }

    // export to textured sphere
    myIFS exportToIFS(const double r = 1.0, const double numpts = 100)
    {
        myIFS result;
        result.useTextureCoordinates = true;

        const double inclinationStep = (PI / numpts);
        const double azimuthStep = (2.0*PI / numpts);

        const Vec3d delta1(azimuthStep, 0, 0);
        const Vec3d delta2(azimuthStep, inclinationStep, 0);
        const Vec3d delta3(0, inclinationStep, 0);

        const Vec2f txd1(azimuthStep, 0);
        const Vec2f txd2(azimuthStep, inclinationStep);
        const Vec2f txd3(0, inclinationStep);
        const Vec2f txnorm(1.0/(2.0*PI), 1.0/PI);

        // create points on a sphere
        for (double e = 0; e < PI; e += inclinationStep)
        {
            for (double a = 0; a < 2 * PI; a += azimuthStep)
            {
                const Vec3d spherical(a, e, r);
                const Vec2f texcoord(a, e);

                std::set<myIFS::IFSINDEX> face;
                myIFS::IFSFACE ifsface;

                auto insertVertex = [&face, &ifsface](myIFS::IFSINDEX i)
                {
                    face.insert(i);
                    ifsface.push_back(i);
                };

                insertVertex(result.vertex2index(spher2cart(spherical), texcoord.elMul(txnorm)));
                insertVertex(result.vertex2index(spher2cart(spherical + delta1), (texcoord + txd1).elMul(txnorm)));
                insertVertex(result.vertex2index(spher2cart(spherical + delta2), (texcoord + txd2).elMul(txnorm)));
                insertVertex(result.vertex2index(spher2cart(spherical + delta3), (texcoord + txd3).elMul(txnorm)));
                // process only non-degenerated faces
                if (face.size() == 4)
                {
                    result.faces.push_back(ifsface);
                }
            }
        }

        return result;
    }
};

template< class T >
struct Quad3D
{
    T V[4];

    // vertices are given in CCW order
    Quad3D(const T &v0, const T &v1, const T &v2, const T &v3)
    {
        // we assume that the Z direction corresponds to the up direction in world space
        // therefore, order the points such that the points with maximum z coordinate
        // are given first, without changing the orientation
        typedef std::pair<double, unsigned int> vdat;

        std::vector < vdat > brak;
        const struct bcomp {
            inline bool operator() (const vdat &A, const vdat &B) const
            {
                return A.first < B.first;
            }
        } brakComp;

        brak.push_back(vdat(v0[2] + v1[2], 0));
        brak.push_back(vdat(v1[2] + v2[2], 1));
        brak.push_back(vdat(v2[2] + v3[2], 2));
        brak.push_back(vdat(v3[2] + v0[2], 3));
        std::sort(brak.begin(), brak.end(), brakComp);
        switch (brak[3].second)
        {
            case 0: V[0] = v0; V[1] = v1; V[2] = v2; V[3] = v3; break;
            case 1: V[0] = v1; V[1] = v2; V[2] = v3; V[3] = v0; break;
            case 2: V[0] = v2; V[1] = v3; V[2] = v0; V[3] = v1; break;
            case 3: V[0] = v3; V[1] = v0; V[2] = v1; V[3] = v2; break;
            default:
            std::abort();
        }
    }

    // resolution is <world units>/pixel
    Image performProjection(const ImageProjection& projection, double resolution) const
    {
#ifdef WRITE_POINTCLOUD_PER_FACE
        static int imagecounter = 0;
        std::ostringstream ss;
        ss << "cloud_" << imagecounter << ".xyz";
        std::ofstream pclfile(ss.str());
        ++imagecounter;
#endif

        // origin is left top
        T W  = V[1] - V[0];
        T H = V[3] - V[0];

        double width = W.length();
        double height = H.length();

        // get image space X and Y directional vectors in world coordinates
        T xdir = W; xdir.normalize();
        T ydir = H; ydir.normalize();

        Image img;
        img.initialize((int)(width/resolution)+1, (int)(height/resolution)+1, 24);

        for (int y = 0; y < img.height(); ++y)
        {
            const T vecy = H * (y / (double)img.height());
            for (int x = 0; x < img.width(); ++x)
            {
                // calculate position in world coordinates
                const T vecx = W * (x / (double)img.width());
                const T position = V[0] + vecx + vecy;

                // project color value
                RGB color = projection.getColorProjection(position);

                // write color value
                img(x, y, 0) = color[0];
                img(x, y, 1) = color[1];
                img(x, y, 2) = color[2];

#ifdef WRITE_POINTCLOUD_PER_FACE
                // write pointcloud file
                std::ostringstream pclpoint;
                pclpoint << position[0] << " " << position[1] << " " << position[2];
                pclpoint << " " << (int)color[0] << " " << (int)color[1] << " " << (int)color[2];
                pclfile << pclpoint.str() << std::endl;
#endif

            }
        }

        return img;
    }

};
typedef Quad3D<Vec3d> Quad3Dd;

// TODO: additional projection types?
//       - fisheye camera dewarping
//       - HomographyProjection from a planar image

int main(int ac, char* av[])
{
    SphericalPanoramaImageProjection projection;
    myIFS ingeometry;
    double resolution = 1.0;        // default: 1 mm/pixel

    std::cout << "OrthoGen orthographic image generator for DuraArk" << std::endl;

    try
    {
        po::options_description desc("commandline options");
        desc.add_options()
            ("help", "show this help message")
            ("im", po::value< std::string >(), "input panoramic image [.PNM]")
            ("ig", po::value< std::string >(), "input geometry [.OBJ]")
            ("res", po::value< double >(), "resolution [mm/pixel]")
            ("rot", po::value< std::vector<double> >()->multitoken(), "rotation quaternion [x,y,z,w]")
            ("elmin", po::value< double >(), "elevation min")
            ("elmax", po::value< double >(), "elevation max")
            ;

        po::variables_map vm;
        po::store(po::parse_command_line(ac, av, desc), vm);
        po::notify(vm);

        if (vm.count("help"))
        {
            std::cout << desc << "\n";
            return 0;
        }

        if (vm.count("im"))
        {
            // load pnm image
            projection.setPanoramicImage(PNM::loadPNM(vm["im"].as<std::string>()));
            if (!projection.img().isValid())
                std::cout << "Error: could not open "
                          << vm["im"].as<std::string>() << std::endl;
        }

        if (vm.count("ig"))
        {
            // load pnm image
            ingeometry = IFS::loadOBJ<myIFS>(vm["ig"].as<std::string>());
            if (!ingeometry.isValid())
                std::cout << "Error: could not open "
                          << vm["ig"].as<std::string>() << std::endl;
        }

        if (vm.count("res"))
        {
            resolution = vm["res"].as<double>();
        }

        if (vm.count("rot"))
        {
            std::vector<double> rot = vm["rot"].as<std::vector<double> >();
            if (rot.size() == 4)
            {
                Quaterniond quaternion(rot[0], rot[1], rot[2], rot[3]);
                std::cout << " applying quaternion [" << quaternion.a << ","
                    << quaternion.b << "," << quaternion.c << "," << quaternion.d
                    << "]" << std::endl;
                projection.applyRotation(quaternion);
            }
            else
            {
                std::cout << " --rot Error: quaternion is not composed of 4 values."
                          << std::endl;
            }
        }

        if (vm.count("elmin"))
        {
            projection.elevationRange[0] = vm["elmin"].as<double>();
        }
        if (vm.count("elmax"))
        {
            projection.elevationRange[1] = vm["elmax"].as<double>();
        }

    }
    catch(std::exception& e)
    {
        std::cerr << "error: " << e.what() << "\n";
        return 1;
    }

    if (projection.isValid() && ingeometry.isValid())
    {
        const Image &img = projection.img();
        //PNM::writePNM(img, "projection.pnm");
        std::cout << "input image is " << img.width() << " x " << img.height() << " pixels." << std::endl;
        std::cout << "input geometry consists of " << ingeometry.vertices.size() << " vertices and " << ingeometry.faces.size() << " faces." << std::endl;
        std::cout << "using a resolution of " << resolution << "mm/pixel" << std::endl;

        // PROCESS OUTPUT
        myIFS sphere = projection.exportToIFS(1000.0);
        IFS::exportOBJ(sphere, "sphere.obj");

        // TODO:
        // - input E57 image to read in pose (position / orientation)
        // - model position and orientation of pano
        // for each face:
        //   for each pixel: perform ray intersection with pano
        //   write output image

        int faceid = 0;
        for (auto const &face : ingeometry.faces)
        {
            if (face.size() == 4)
            {
                // create quad in 3D
                Quad3Dd quad(ingeometry.vertices[face[0]],
                             ingeometry.vertices[face[1]],
                             ingeometry.vertices[face[2]],
                             ingeometry.vertices[face[3]]);
                // raster quad
                Image orthophoto = quad.performProjection(projection, resolution);
                {
                    std::ostringstream oss;
                    oss << "ortho_" << faceid << ".pnm";
                    PNM::writePNM(orthophoto, oss.str());
                    std::cout << oss.str() << " : " << orthophoto.width() << "x" << orthophoto.height() << std::endl;
                }
            }
            else
            {
                std::cout << "[ERR]: non-quad face detected (" << face.size() << " vertices)." << std::endl;
            }
            ++faceid;
        }

        return 0;
    }

    std::cout << "--help for options." << std::endl;

}<|endoftext|>


<commit_before>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/system_monitor.h"

namespace base {

void SystemMonitor::ProcessWmPowerBroadcastMessage(int event_id) {
  PowerEvent power_event;
  switch (event_id) {
    case PBT_APMPOWERSTATUSCHANGE:
      power_event = POWER_STATE_EVENT;
      break;
    case PBT_APMRESUMEAUTOMATIC:
      power_event = RESUME_EVENT;
      break;
    case PBT_APMSUSPEND:
      power_event = SUSPEND_EVENT;
      break;
    default:
      DCHECK(false);
  }
  ProcessPowerMessage(power_event);
}

// Function to query the system to see if it is currently running on
// battery power.  Returns true if running on battery.
bool SystemMonitor::IsBatteryPower() {
  SYSTEM_POWER_STATUS status;
  if (!GetSystemPowerStatus(&status)) {
    LOG(ERROR) << "GetSystemPowerStatus failed: " << GetLastError();
    return false;
  }
  return (status.ACLineStatus == 0);
}

} // namespace base
<commit_msg>Update comments and remove bogus DCHECK in windows-specific broadcasted power message status.<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/system_monitor.h"

namespace base {

void SystemMonitor::ProcessWmPowerBroadcastMessage(int event_id) {
  PowerEvent power_event;
  switch (event_id) {
    case PBT_APMPOWERSTATUSCHANGE:  // The power status changed.
      power_event = POWER_STATE_EVENT;
      break;
    case PBT_APMRESUMEAUTOMATIC:  // Non-user initiated resume from suspend.
    case PBT_APMRESUMESUSPEND:    // User initiated resume from suspend.
      power_event = RESUME_EVENT;
      break;
    case PBT_APMSUSPEND:  // System has been suspended.
      power_event = SUSPEND_EVENT;
      break;
    default:
      return;

    // Other Power Events:
    // PBT_APMBATTERYLOW - removed in Vista.
    // PBT_APMOEMEVENT - removed in Vista.
    // PBT_APMQUERYSUSPEND - removed in Vista.
    // PBT_APMQUERYSUSPENDFAILED - removed in Vista.
    // PBT_APMRESUMECRITICAL - removed in Vista.
    // PBT_POWERSETTINGCHANGE - user changed the power settings.
  }
  ProcessPowerMessage(power_event);
}

// Function to query the system to see if it is currently running on
// battery power.  Returns true if running on battery.
bool SystemMonitor::IsBatteryPower() {
  SYSTEM_POWER_STATUS status;
  if (!GetSystemPowerStatus(&status)) {
    LOG(ERROR) << "GetSystemPowerStatus failed: " << GetLastError();
    return false;
  }
  return (status.ACLineStatus == 0);
}

} // namespace base
<|endoftext|>


<commit_before>
/**
 * Simple QtWeb
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#include <QtGui/QApplication>
#include <QObject>

#include <QDebug>

#include <QWebView>
#include <QWebFrame>
#include <QUrl>
#include <QWebElement>
#include <QPoint>
#include <QRect>
#include <QMouseEvent>
#include <QCursor>
#include <QStringList>
#include <QNetworkProxy>
#include <QSocketNotifier>
#include <QTextStream>

#include <memory>

#include <signal.h>
#include <unistd.h> // STDIN_FILENO

#include "lambda.h"
#include "qwebpage.h"

std::unique_ptr<QWebView> view;
std::unique_ptr<QSocketNotifier> stdinNotifier;

struct Options {
	bool maximize;
	QString url; // default url is "kernel.org"
	QString userAgent; // default is that using in ga-kw
	QString socks;
	QString moveToElementPrefix;
	QString clickToElementPrefix;
	QString cursorSetToElementPrefix;
	bool socksResolver;
};
// Set default options
Options options = {
	false,
	QString("kernel.org"),
	QString("Mozilla/5.0 (X11; U; Linux i686;) Gecko/20110101 Firefox/3.6.13"),
	QString(""),
	QString("Move to "),
	QString("Click to "),
	QString("Cursor to "),
	false,
};

QStringList getCliArguments(int argc, char** argv) {
	QStringList cliArguments;

	for (int i = 0; i < argc; ++i) {
		cliArguments << QString::fromLocal8Bit(argv[i]);
	}

	return cliArguments;
}

int main(int argc, char** argv) {
	// Parse options
	// TODO: http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKCmdLineArgs.html
	{
		QStringList arguments = getCliArguments(argc, argv);
		if ((arguments.indexOf("-h") != -1) || (arguments.indexOf("--help") != -1)) {
			qDebug() << "QtWeb options:";
			qDebug() << "";
			qDebug() << "--maximize";
			qDebug() << "";
			qDebug() << "--url";
			qDebug() << "--user-agent";
			qDebug() << "--socks host:port";
			qDebug() << "--socks-resolver";

			return EXIT_SUCCESS;
		}

		int optionIndex = 0;

		// maximize
		if ((optionIndex = arguments.indexOf("--maximize")) != -1) {
			options.maximize = true;
		}
		// url
		if ((optionIndex = arguments.indexOf("--url")) != -1) {
			options.url = arguments.at(optionIndex + 1);
		}
		// user agent
		if ((optionIndex = arguments.indexOf("--user-agent")) != -1) {
			options.userAgent = arguments.at(optionIndex + 1);
			Wrapper::QWebPage::userAgent = options.userAgent;
		}
		// socks
		if ((optionIndex = arguments.indexOf("--socks")) != -1) {
			options.socks = arguments.at(optionIndex + 1);
		}
		// socks resolver
		if ((optionIndex = arguments.indexOf("--socks-resolver")) != -1) {
			options.socksResolver = true;
		}

		qDebug() << "Maximize" << options.maximize;
		qDebug() << "Load" << options.url;
		qDebug() << "User-agent" << options.userAgent;
		qDebug() << "Socks" << options.socks;
		qDebug() << "Socks resolver" << options.socksResolver;
	}

	QApplication a(argc, argv);

	// release view
	Lambda qHandler([&]() {
		view.reset();
	});
	QObject::connect(&a, SIGNAL(aboutToQuit()), &qHandler, SLOT(call()));

	view.reset(new QWebView);
	view->setPage(new Wrapper::QWebPage);

	// add "http://"
	if (options.url.indexOf("://") == -1) {
		options.url = QLatin1String("http://") + options.url;
	}

	// socks
	if (options.socks.length()) {
		QNetworkProxy proxy;
		proxy.setType(QNetworkProxy::Socks5Proxy);

		int colonPosition = options.socks.lastIndexOf(":");
		if (colonPosition == -1) {
			qDebug() << "Malformed proxy (HOST:PORT is needed)";
			return EXIT_FAILURE;
		}

		proxy.setHostName(options.socks.left(colonPosition));
		proxy.setPort(options.socks.right(options.socks.length() - 1 - colonPosition).toInt());

		if (options.socksResolver) {
			proxy.setCapabilities(proxy.capabilities() | QNetworkProxy::HostNameLookupCapability);
		} else {
			proxy.setCapabilities(proxy.capabilities() & ~QNetworkProxy::HostNameLookupCapability);
		}

		view->page()->networkAccessManager()->setProxy(proxy);

		qDebug() << "Proxy installed";
	}

    // Add inspector.
	view->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);

	view->load(QUrl(options.url));
	if (options.maximize) {
		view->showMaximized();
	} else {
		view->show();
	}

	// execute JS
	{
		// Reinterpret pointer to Wrapper class
		Wrapper::QWebPage *page = reinterpret_cast<Wrapper::QWebPage *>(view->page());

		// async read from STDIN
		// and eval this as JS code
		stdinNotifier.reset(new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read));
		QObject::connect(&(*stdinNotifier), SIGNAL(activated(int)), new Lambda([&] {
			qDebug() << Q_FUNC_INFO;

			QTextStream stream(stdin, QIODevice::ReadOnly);
			QString jsToExecute;

			forever {
				fd_set stdinfd;
				FD_ZERO( &stdinfd );
				FD_SET( STDIN_FILENO, &stdinfd );
				struct timeval tv;
				tv.tv_sec = 0;
				tv.tv_usec = 0;
				int ready = select(1, &stdinfd, NULL, NULL, &tv);

				if (ready > 0) {
					jsToExecute += stream.readLine();
				} else {
					break;
				}
			}

			// TODO : drop code duplicating
			if (jsToExecute.startsWith(options.moveToElementPrefix)) {
				QString moveMouseToElementSelector = jsToExecute.remove(0, options.moveToElementPrefix.length());

				page->moveMouseTo(page->mainFrame()->findFirstElement(moveMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.clickToElementPrefix)) {
				QString clickMouseToElementSelector = jsToExecute.remove(0, options.clickToElementPrefix.length());

				page->clickTo(page->mainFrame()->findFirstElement(clickMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.cursorSetToElementPrefix)) {
				QString setCursorToElementSelector = jsToExecute.remove(0, options.cursorSetToElementPrefix.length());

				page->setCursorTo(page->mainFrame()->findFirstElement(setCursorToElementSelector));
			} else {
				view->page()->mainFrame()->evaluateJavaScript(jsToExecute);
			}
		}), SLOT(call()));
		stdinNotifier->setEnabled(true);
	}

	return a.exec();
}

<commit_msg>Add "--extra-enabled" option<commit_after>
/**
 * Simple QtWeb
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#include <QtGui/QApplication>
#include <QObject>

#include <QDebug>

#include <QWebView>
#include <QWebFrame>
#include <QUrl>
#include <QWebElement>
#include <QPoint>
#include <QRect>
#include <QMouseEvent>
#include <QCursor>
#include <QStringList>
#include <QNetworkProxy>
#include <QSocketNotifier>
#include <QTextStream>

#include <memory>

#include <signal.h>
#include <unistd.h> // STDIN_FILENO

#include "lambda.h"
#include "qwebpage.h"

std::unique_ptr<QWebView> view;
std::unique_ptr<QSocketNotifier> stdinNotifier;

struct Options {
	bool maximize;
	QString url; // default url is "kernel.org"
	QString userAgent; // default is that using in ga-kw
	QString socks;
	QString moveToElementPrefix;
	QString clickToElementPrefix;
	QString cursorSetToElementPrefix;
	bool socksResolver;
	bool extraEnabled; // some extra stuff for QWebPage
};
// Set default options
Options options = {
	false,
	QString("kernel.org"),
	QString("Mozilla/5.0 (X11; U; Linux i686;) Gecko/20110101 Firefox/3.6.13"),
	QString(""),
	QString("Move to "),
	QString("Click to "),
	QString("Cursor to "),
	false,
	false,
};

QStringList getCliArguments(int argc, char** argv) {
	QStringList cliArguments;

	for (int i = 0; i < argc; ++i) {
		cliArguments << QString::fromLocal8Bit(argv[i]);
	}

	return cliArguments;
}

int main(int argc, char** argv) {
	// Parse options
	// TODO: http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKCmdLineArgs.html
	{
		QStringList arguments = getCliArguments(argc, argv);
		if ((arguments.indexOf("-h") != -1) || (arguments.indexOf("--help") != -1)) {
			qDebug() << "QtWeb options:";
			qDebug() << "";
			qDebug() << "--maximize";
			qDebug() << "";
			qDebug() << "--url";
			qDebug() << "--user-agent";
			qDebug() << "--socks host:port";
			qDebug() << "--socks-resolver";
			qDebug() << "--extra-enabled";

			return EXIT_SUCCESS;
		}

		int optionIndex = 0;

		// maximize
		if ((optionIndex = arguments.indexOf("--maximize")) != -1) {
			options.maximize = true;
		}
		// url
		if ((optionIndex = arguments.indexOf("--url")) != -1) {
			options.url = arguments.at(optionIndex + 1);
		}
		// user agent
		if ((optionIndex = arguments.indexOf("--user-agent")) != -1) {
			options.userAgent = arguments.at(optionIndex + 1);
			Wrapper::QWebPage::userAgent = options.userAgent;
		}
		// socks
		if ((optionIndex = arguments.indexOf("--socks")) != -1) {
			options.socks = arguments.at(optionIndex + 1);
		}
		// socks resolver
		if ((optionIndex = arguments.indexOf("--socks-resolver")) != -1) {
			options.socksResolver = true;
		}
		// enable extra
		if ((optionIndex = arguments.indexOf("--extra-enabled")) != -1) {
			options.extraEnabled = true;
		}

		qDebug() << "Maximize" << options.maximize;
		qDebug() << "Load" << options.url;
		qDebug() << "User-agent" << options.userAgent;
		qDebug() << "Socks" << options.socks;
		qDebug() << "Socks resolver" << options.socksResolver;
		qDebug() << "Extra enabled" << options.extraEnabled;
	}

	QApplication a(argc, argv);

	// release view
	Lambda qHandler([&]() {
		view.reset();
	});
	QObject::connect(&a, SIGNAL(aboutToQuit()), &qHandler, SLOT(call()));

	view.reset(new QWebView);
	view->setPage(new Wrapper::QWebPage);

	// add "http://"
	if (options.url.indexOf("://") == -1) {
		options.url = QLatin1String("http://") + options.url;
	}

	// socks
	if (options.socks.length()) {
		QNetworkProxy proxy;
		proxy.setType(QNetworkProxy::Socks5Proxy);

		int colonPosition = options.socks.lastIndexOf(":");
		if (colonPosition == -1) {
			qDebug() << "Malformed proxy (HOST:PORT is needed)";
			return EXIT_FAILURE;
		}

		proxy.setHostName(options.socks.left(colonPosition));
		proxy.setPort(options.socks.right(options.socks.length() - 1 - colonPosition).toInt());

		if (options.socksResolver) {
			proxy.setCapabilities(proxy.capabilities() | QNetworkProxy::HostNameLookupCapability);
		} else {
			proxy.setCapabilities(proxy.capabilities() & ~QNetworkProxy::HostNameLookupCapability);
		}

		view->page()->networkAccessManager()->setProxy(proxy);

		qDebug() << "Proxy installed";
	}

    // Add inspector.
	view->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
	if (options.extraEnabled) {
		view->page()->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
		view->page()->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
		view->page()->settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, true);
		view->page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
		view->page()->settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
	}

	view->load(QUrl(options.url));
	if (options.maximize) {
		view->showMaximized();
	} else {
		view->show();
	}

	// execute JS
	{
		// Reinterpret pointer to Wrapper class
		Wrapper::QWebPage *page = reinterpret_cast<Wrapper::QWebPage *>(view->page());

		// async read from STDIN
		// and eval this as JS code
		stdinNotifier.reset(new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read));
		QObject::connect(&(*stdinNotifier), SIGNAL(activated(int)), new Lambda([&] {
			qDebug() << Q_FUNC_INFO;

			QTextStream stream(stdin, QIODevice::ReadOnly);
			QString jsToExecute;

			forever {
				fd_set stdinfd;
				FD_ZERO( &stdinfd );
				FD_SET( STDIN_FILENO, &stdinfd );
				struct timeval tv;
				tv.tv_sec = 0;
				tv.tv_usec = 0;
				int ready = select(1, &stdinfd, NULL, NULL, &tv);

				if (ready > 0) {
					jsToExecute += stream.readLine();
				} else {
					break;
				}
			}

			// TODO : drop code duplicating
			if (jsToExecute.startsWith(options.moveToElementPrefix)) {
				QString moveMouseToElementSelector = jsToExecute.remove(0, options.moveToElementPrefix.length());

				page->moveMouseTo(page->mainFrame()->findFirstElement(moveMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.clickToElementPrefix)) {
				QString clickMouseToElementSelector = jsToExecute.remove(0, options.clickToElementPrefix.length());

				page->clickTo(page->mainFrame()->findFirstElement(clickMouseToElementSelector));
			} else if (jsToExecute.startsWith(options.cursorSetToElementPrefix)) {
				QString setCursorToElementSelector = jsToExecute.remove(0, options.cursorSetToElementPrefix.length());

				page->setCursorTo(page->mainFrame()->findFirstElement(setCursorToElementSelector));
			} else {
				view->page()->mainFrame()->evaluateJavaScript(jsToExecute);
			}
		}), SLOT(call()));
		stdinNotifier->setEnabled(true);
	}

	return a.exec();
}

<|endoftext|>


<commit_before><commit_msg>Change the stub for file_util::EvictFileFromSystemCache<commit_after><|endoftext|>