<commit_before>/*  Sirikata Configuration Options -- Sirikata Options
 *  Options.cpp
 *
 *  Copyright (c) 2009, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "util/Platform.hpp"
#include "Options.hpp"
#include "boost/thread.hpp"
#include "boost/program_options.hpp"
#include <iostream>
#include <stdarg.h>

namespace Sirikata {
namespace {
//from boost
	    std::vector<std::string> splice_winmain(const std::string& input)
 	    {
 	        std::vector<std::string> result;
            using std::string;
 	        string::const_iterator i = input.begin(), e = input.end();
 	        for(;i != e; ++i)
 	            if (!isspace(*i))
 	                break;

 	        if (i != e) {

 	            std::string current;
 	            bool inside_quoted = false;
 	            int backslash_count = 0;

	            for(; i != e; ++i) {
 	                if (*i == '"') {
 	                    // '"' preceded by even number (n) of backslashes generates
                 // n/2 backslashes and is a quoted block delimiter
 	                    if (backslash_count % 2 == 0) {
 	                        current.append(backslash_count / 2, '\\');
 	                        inside_quoted = !inside_quoted;
 	                        // '"' preceded by odd number (n) of backslashes generates
 	                        // (n-1)/2 backslashes and is literal quote.
 	                    } else {
 	                        current.append(backslash_count / 2, '\\');
 	                        current += '"';
 	                    }
 	                    backslash_count = 0;
 	                } else if (*i == '\\') {
 	                    ++backslash_count;
 	                } else {
 	                    // Not quote or backslash. All accumulated backslashes should be
 	                    // added
 	                    if (backslash_count) {
 	                        current.append(backslash_count, '\\');
 	                        backslash_count = 0;
 	                    }
 	                    if (isspace(*i) && !inside_quoted) {
 	                        // Space outside quoted section terminate the current argument
 	                        result.push_back(current);
 	                        current.resize(0);
 	                        for(;i != e && isspace(*i); ++i)
 	                            ;
 	                        --i;
 	                    } else {
 	                        current += *i;
 	                    }
 	                }
 		        }

 	            // If we have trailing backslashes, add them
 	            if (backslash_count)
 	                current.append(backslash_count, '\\');

 	            // If we have non-empty 'current' or we're still in quoted
 	            // section (even if 'current' is empty), add the last token.
 	            if (!current.empty() || inside_quoted)
 	                result.push_back(current);
 	        }
 	        return result;
 	    }

}
class OptionRegistration {
public:
    static boost::mutex & OptionSetMutex() {
        static boost::mutex mutex;
        return mutex;
    }
    static void register_options(const std::map<std::string,OptionValue*>&names, boost::program_options::options_description &options) {
        for (std::map<std::string,OptionValue*>::const_iterator i=names.begin(),ie=names.end();
             i!=ie;
             ++i) {
            options.add_options()(i->second->mName,
                                  boost::program_options::value<std::string>()->default_value(i->second->defaultValue()),
                                  i->second->description());
        }
    }
    static bool update_options(std::map<std::string,OptionValue*>&names, boost::program_options::options_description &options_description, const boost::program_options::variables_map options) {
        if (options.count("help")){
            try {
                std::cout << options_description;
            }
            catch (...) {
                std::cout << "Ran out of options to display!" << std::endl;
                return false;
            }
            return false;
        }
        if (options.count("TESTO"))
            assert(false);
        for (std::map<std::string,OptionValue*>::iterator i=names.begin(),ie=names.end();
             i!=ie;
             ++i) {
				 if (options.count(i->first)){
					 const std::string * s=boost::any_cast<const std::string>(&options[i->first].value());
                     assert(s!=NULL);
                     i->second->mValue.newAndDoNotFree(i->second->mParser(*s));
				 }
        }
        return true;
    }
};
bool OptionValue::initializationSet(const OptionValue&other) {
    if (mParser==NULL){
        mValue.newAndDoNotFree(other.mValue);
        mDefaultValue=other.mDefaultValue;
        mDescription=other.mDescription;
        mParser=other.mParser;
        mChangeFunction=other.mChangeFunction;
        mName=other.mName;
        return true;
    }else if (other.mParser==NULL) {
        return true;
    }else {
        return false;
    }
}

OptionValue& OptionValue::operator=(const OptionValue&other) {
    Any oldValue=mValue;
    mValue.newAndDoNotFree(other.mValue);
    mDefaultValue=other.mDefaultValue;
    mDescription=other.mDescription;
    mParser=other.mParser;
    mChangeFunction(mName,oldValue,mValue);
    mChangeFunction=other.mChangeFunction;
    mName=other.mName;
    return *this;
}
void OptionSet::parse(int argc, const char **argv){
    boost::program_options::options_description options;
    boost::program_options::variables_map output;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        OptionRegistration::register_options(mNames,options);
    }
    options.add_options()("help","Print available options");
    boost::program_options::store( parse_command_line(argc, const_cast<char**>(argv), options), output);
    bool dienow=false;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        dienow=!OptionRegistration::update_options(mNames,options,output);
    }
    if (dienow)
        exit(0);
}
void OptionSet::parse(const std::string&args){
    boost::program_options::options_description options;
    boost::program_options::variables_map output;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        OptionRegistration::register_options(mNames,options);
    }
    options.add_options()("help","Print available options");
    std::vector<std::string> args_vec = splice_winmain(args);
    boost::program_options::store( boost::program_options::command_line_parser(args_vec).options(options).run(),output);
    bool dienow=false;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        dienow=!OptionRegistration::update_options(mNames,options,output);
    }
    if (dienow)
        exit(0);
}
OptionSet* OptionSet::getOptionsNoLock(const std::string&s){
    std::map<std::string,OptionSet*>::iterator i=optionSets()->find(s);
    if (i==optionSets()->end()){
        return (*optionSets())[s]=new OptionSet;
    }else{
        return i->second;
    }
}
OptionSet* OptionSet::getOptions(const std::string&s){
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    return getOptionsNoLock(s);
}
OptionValue* OptionSet::referenceOption(const std::string&module, const std::string&option,OptionValue**pointer) {
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    return getOptionsNoLock(module)->referenceOptionNoLock(option,pointer);
}
OptionValue* OptionSet::referenceOptionNoLock(const std::string&option,OptionValue**pointer) {
    std::map<std::string,OptionValue*>::iterator where=mNames.find(option);
    if (where==mNames.end()) {
        OptionValue* newed=new OptionValue;
        if (pointer!=NULL)
            *pointer=newed;
        return mNames[option]=newed;
    }else {
        return where->second;
    }
}
OptionValue* OptionSet::referenceOption(const std::string&option,OptionValue**pointer) {
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    return referenceOptionNoLock(option,pointer);
}
void OptionSet::addOptionNoLock(OptionValue*option) {
    std::map<std::string,OptionValue*>::iterator where=mNames.find(option->mName);
    if (where==mNames.end()) {
        mNames[option->mName]=option;
    }else {
        where->second->initializationSet(*option);
        delete option;
    }
}
void OptionSet::addOption(OptionValue *option) {
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    addOptionNoLock(option);
}

InitializeOptions::InitializeOptions(const char * module,...) {
    va_list vl;
    va_start(vl,module);
    OptionValue* option;
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    OptionSet* curmodule=OptionSet::getOptionsNoLock(module);
    while ((option=va_arg(vl,OptionValue*))!=NULL) {
        curmodule->addOptionNoLock(option);
    }

}
}
<commit_msg>trying a nonspecialized version of string for program_options<commit_after>/*  Sirikata Configuration Options -- Sirikata Options
 *  Options.cpp
 *
 *  Copyright (c) 2009, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "util/Platform.hpp"
#include "Options.hpp"
#include "boost/thread.hpp"
#include "boost/program_options.hpp"
#include <iostream>
#include <stdarg.h>

namespace Sirikata {
class simple_string:public std::string {
public:
    simple_string(const std::string&other):std::string(other){

    }
/*
    char * data;
    unsigned int len;

    simple_string() {
        data=NULL;
        len=0;
    }
    simple_string(const std::string&s) {
        if (s.length()) {
            data=new char[s.length()];
            len=s.length();
            memcpy(data,s.data(),s.length());
        }else {
            data=NULL;
            len=0;
        }
    }
    simple_string(const std::vector<char>&other) {
        if (other.size()) {
            data= new char(other.size());
            memcpy(data,&*other.begin(),other.size());
            len=other.size();
        }else {
            len=0;
            data=NULL;
        }

    }
    simple_string(const simple_string&other) {
        if (other.len) {
            data=new char[other.len];
            len=other.len;
            memcpy(data,other.data,other.len);
        }else {
            len=0;
            data=NULL;
        }
    }
    simple_string&operator=(const simple_string&other) {
        if (other.len) {
            data=new char[other.len];
            len=other.len;
            memcpy(data,other.data,other.len);
        }else {
            len=0;
            data=NULL;
        }
        return *this;
    }
    ~simple_string() {
        delete []data;
    }
    operator std::string() {
        return std::string(data,len);
    }
*/
};
void validate(boost::any& v, const std::vector<String>& values, Sirikata::simple_string* target_type, int){
    using namespace boost;
    using namespace boost::program_options;

    // no previous instances
    validators::check_first_occurrence(v);
    // only one string in values
    v=any(simple_string(validators::get_single_string(values)));
}
}
/*
std::basic_ostream<char>& operator<< (std::basic_ostream<char>&is,const Sirikata::simple_string &output) {
    is<<output//std::string(output.data,output.len);
    return is;
}

std::istream &operator >>(std::istream &is,Sirikata::simple_string &output) {
    std::vector<char> test;
    while (!is.eof()) {
        char ch[1024];
        is.get(ch,1023);
        std::vector<char>::size_type adv=is.gcount();
        if (adv)
            test.insert(test.end(),ch,ch+adv);
    }
    output=Sirikata::simple_string(test);
    return is;
}
*/
namespace Sirikata {
namespace {
//from boost
	    std::vector<std::string> splice_winmain(const std::string& input)
 	    {
 	        std::vector<std::string> result;
            using std::string;
 	        string::const_iterator i = input.begin(), e = input.end();
 	        for(;i != e; ++i)
 	            if (!isspace(*i))
 	                break;

 	        if (i != e) {

 	            std::string current;
 	            bool inside_quoted = false;
 	            int backslash_count = 0;

	            for(; i != e; ++i) {
 	                if (*i == '"') {
 	                    // '"' preceded by even number (n) of backslashes generates
                 // n/2 backslashes and is a quoted block delimiter
 	                    if (backslash_count % 2 == 0) {
 	                        current.append(backslash_count / 2, '\\');
 	                        inside_quoted = !inside_quoted;
 	                        // '"' preceded by odd number (n) of backslashes generates
 	                        // (n-1)/2 backslashes and is literal quote.
 	                    } else {
 	                        current.append(backslash_count / 2, '\\');
 	                        current += '"';
 	                    }
 	                    backslash_count = 0;
 	                } else if (*i == '\\') {
 	                    ++backslash_count;
 	                } else {
 	                    // Not quote or backslash. All accumulated backslashes should be
 	                    // added
 	                    if (backslash_count) {
 	                        current.append(backslash_count, '\\');
 	                        backslash_count = 0;
 	                    }
 	                    if (isspace(*i) && !inside_quoted) {
 	                        // Space outside quoted section terminate the current argument
 	                        result.push_back(current);
 	                        current.resize(0);
 	                        for(;i != e && isspace(*i); ++i)
 	                            ;
 	                        --i;
 	                    } else {
 	                        current += *i;
 	                    }
 	                }
 		        }

 	            // If we have trailing backslashes, add them
 	            if (backslash_count)
 	                current.append(backslash_count, '\\');

 	            // If we have non-empty 'current' or we're still in quoted
 	            // section (even if 'current' is empty), add the last token.
 	            if (!current.empty() || inside_quoted)
 	                result.push_back(current);
 	        }
 	        return result;
 	    }

}
class OptionRegistration {
public:
    static boost::mutex & OptionSetMutex() {
        static boost::mutex mutex;
        return mutex;
    }
    static void register_options(const std::map<std::string,OptionValue*>&names, boost::program_options::options_description &options) {
        for (std::map<std::string,OptionValue*>::const_iterator i=names.begin(),ie=names.end();
             i!=ie;
             ++i) {
            options.add_options()(i->second->mName,
                                  boost::program_options::value<simple_string>()->default_value(simple_string(i->second->defaultValue())),
                                  i->second->description());
        }
    }
    static bool update_options(std::map<std::string,OptionValue*>&names, boost::program_options::options_description &options_description, const boost::program_options::variables_map options) {
        if (options.count("help")){
            try {
                std::cout << options_description;
            }
            catch (...) {
                std::cout << "Ran out of options to display!" << std::endl;
                return false;
            }
            return false;
        }
        if (options.count("TESTO"))
            assert(false);
        for (std::map<std::string,OptionValue*>::iterator i=names.begin(),ie=names.end();
             i!=ie;
             ++i) {
				 if (options.count(i->first)){
                     const simple_string* s=boost::any_cast<simple_string>(&options[i->first].value());
                     assert(s!=NULL);
                     i->second->mValue.newAndDoNotFree(i->second->mParser(*s));
				 }
        }
        return true;
    }
};
bool OptionValue::initializationSet(const OptionValue&other) {
    if (mParser==NULL){
        mValue.newAndDoNotFree(other.mValue);
        mDefaultValue=other.mDefaultValue;
        mDescription=other.mDescription;
        mParser=other.mParser;
        mChangeFunction=other.mChangeFunction;
        mName=other.mName;
        return true;
    }else if (other.mParser==NULL) {
        return true;
    }else {
        return false;
    }
}

OptionValue& OptionValue::operator=(const OptionValue&other) {
    Any oldValue=mValue;
    mValue.newAndDoNotFree(other.mValue);
    mDefaultValue=other.mDefaultValue;
    mDescription=other.mDescription;
    mParser=other.mParser;
    mChangeFunction(mName,oldValue,mValue);
    mChangeFunction=other.mChangeFunction;
    mName=other.mName;
    return *this;
}
void OptionSet::parse(int argc, const char **argv){
    boost::program_options::options_description options;
    boost::program_options::variables_map output;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        OptionRegistration::register_options(mNames,options);
    }
    options.add_options()("help","Print available options");
    boost::program_options::store( parse_command_line(argc, const_cast<char**>(argv), options), output);
    bool dienow=false;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        dienow=!OptionRegistration::update_options(mNames,options,output);
    }
    if (dienow)
        exit(0);
}
void OptionSet::parse(const std::string&args){
    boost::program_options::options_description options;
    boost::program_options::variables_map output;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        OptionRegistration::register_options(mNames,options);
    }
    options.add_options()("help","Print available options");
    std::vector<std::string> args_vec = splice_winmain(args);
    boost::program_options::store( boost::program_options::command_line_parser(args_vec).options(options).run(),output);
    bool dienow=false;
    {
        boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
        dienow=!OptionRegistration::update_options(mNames,options,output);
    }
    if (dienow)
        exit(0);
}
OptionSet* OptionSet::getOptionsNoLock(const std::string&s){
    std::map<std::string,OptionSet*>::iterator i=optionSets()->find(s);
    if (i==optionSets()->end()){
        return (*optionSets())[s]=new OptionSet;
    }else{
        return i->second;
    }
}
OptionSet* OptionSet::getOptions(const std::string&s){
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    return getOptionsNoLock(s);
}
OptionValue* OptionSet::referenceOption(const std::string&module, const std::string&option,OptionValue**pointer) {
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    return getOptionsNoLock(module)->referenceOptionNoLock(option,pointer);
}
OptionValue* OptionSet::referenceOptionNoLock(const std::string&option,OptionValue**pointer) {
    std::map<std::string,OptionValue*>::iterator where=mNames.find(option);
    if (where==mNames.end()) {
        OptionValue* newed=new OptionValue;
        if (pointer!=NULL)
            *pointer=newed;
        return mNames[option]=newed;
    }else {
        return where->second;
    }
}
OptionValue* OptionSet::referenceOption(const std::string&option,OptionValue**pointer) {
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    return referenceOptionNoLock(option,pointer);
}
void OptionSet::addOptionNoLock(OptionValue*option) {
    std::map<std::string,OptionValue*>::iterator where=mNames.find(option->mName);
    if (where==mNames.end()) {
        mNames[option->mName]=option;
    }else {
        where->second->initializationSet(*option);
        delete option;
    }
}
void OptionSet::addOption(OptionValue *option) {
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    addOptionNoLock(option);
}

InitializeOptions::InitializeOptions(const char * module,...) {
    va_list vl;
    va_start(vl,module);
    OptionValue* option;
    boost::unique_lock<boost::mutex> lock(OptionRegistration::OptionSetMutex());
    OptionSet* curmodule=OptionSet::getOptionsNoLock(module);
    while ((option=va_arg(vl,OptionValue*))!=NULL) {
        curmodule->addOptionNoLock(option);
    }

}
}
<|endoftext|>


<commit_before>/*
 * Jamoma Foundation
 * Copyright © 2008, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTFoundation.h"
#include "TTSymbolTable.h"
#include "TTEnvironment.h"
#include "TTSymbolCache.h"
#include "TTValueCache.h"
#include "TTCallback.h"
#include "TTNode.h"
#include "TTNodeDirectory.h"
#include "TTPath.h"

// Unit Tests
#include "TTMatrix.h"
#include "TTMatrixArray.h"
#include "TTValue.test.h"

#ifdef TT_PLATFORM_MAC
#include <dlfcn.h>
#elif TT_PLATFORM_LINUX
#include <dlfcn.h>
#elif TT_PLATFORM_WIN
#include <ShlObj.h>
#endif

static bool		TTFoundationHasInitialized = false;
static TTString	TTFoundationBinaryPath = "";

void		TTFoundationLoadExternalClasses();
void		TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath);
TTObjectPtr	TTFoundationInstantiateInternalClass(TTSymbol* className, TTValue& arguments);

/****************************************************************************************************/
void TTFoundationInit(const char* pathToBinaries)
{
	if (!TTFoundationHasInitialized) {
		TTFoundationHasInitialized = true;

		if (pathToBinaries)
			TTFoundationBinaryPath = pathToBinaries;

		ttSymbolTable = new TTSymbolTable;
		for (int i=0; i<kNumTTDataTypes; i++)
			TTDataInfo::addDataInfoForType(TTDataType(i));

		ttEnvironment = new TTEnvironment;

		TTSymbolCacheInit();
		TTValueCacheInit();

#ifdef TT_DEBUG
		TTLogMessage("JamomaFoundation (TT_DEBUG) -- Version %s", TTFOUNDATION_VERSION_STRING);
		ttEnvironment->mDebugBasic = true;
#else
		TTLogMessage("JamomaFoundation -- Version %s", TTFOUNDATION_VERSION_STRING);
#endif
		if (pathToBinaries)
			TTLogMessage("-- Path %s\n", pathToBinaries);
		else
			TTLogMessage("\n");

		// register classes -- both internal and external
		TTCallback::registerClass();
		TTMatrix::registerClass();
		TTMatrixArray::registerClass();
		TTValueTest::registerClass();

		TTFoundationLoadExternalClasses();
	}
}

void TTFoundationShutdown()
{
	// FIXME: How do we call this (i.e. TTDSPShutdown()?) -- do we need to setup an observer of some sort on the environment class?
	// TODO: we need to free singletons like the environment here!
}

/****************************************************************************************************/

void TTFoundationLoadExternalClasses()
{
#ifdef TT_PLATFORM_MAC
	if (!TTFoundationBinaryPath.empty()) {
		// Look in the specified folder rather than the default location
		TTString extensionsPath = TTFoundationBinaryPath + "/Extensions";
		TTFoundationLoadExternalClassesFromFolder(extensionsPath);
	}
	else {
		OSErr		err = noErr;
		FSRef		ref;
		UInt8		path[4096];
		TTString	fullpath;

		// Look in ~/Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}

		// Look in /Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}

		// Look in the folder of the host application
		CFBundleRef mainBundle = CFBundleGetMainBundle();
		CFURLRef	mainBundleURL = CFBundleCopyBundleURL(mainBundle);
		CFStringRef mainBundlePath = CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
		char		mainBundleStr[4096];

		CFStringGetCString(mainBundlePath, mainBundleStr, 4096, kCFStringEncodingUTF8);
		strncat(mainBundleStr, "/Contents/Jamoma/Extensions", 4096);
		mainBundleStr[4095] = 0;
		TTFoundationLoadExternalClassesFromFolder(mainBundleStr);
	}
#elif TT_PLATFORM_WIN
	TTString	fullpath;
	char		temppath[4096];
	HKEY		hKey = 0;
	LONG		lRes;
	DWORD		dwSize = sizeof(temppath);
	HRESULT		hr;
	HINSTANCE	hInstance = GetModuleHandle(NULL);

	// Look in C:\Program Files\Common Files\TTBlue\Extensions
	hr = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_CURRENT, (LPSTR)temppath);
	if (!FAILED(hr)) {
		fullpath = temppath;
		fullpath += "\\Jamoma\\Extensions\\";
		lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
		TTFoundationLoadExternalClassesFromFolder(fullpath);
	}

	// TODO: Look in some user-level directory like we do on the Mac?

	// Look in the support folder of the host application
	if (hInstance) {
		GetModuleFileName(hInstance, (LPSTR)temppath, 4096);
		if (temppath[0]) {
			char *s = strrchr(temppath, '\\');
			if (s)
				*s = 0;
			fullpath = temppath;
			fullpath += "\\Jamoma\\Extensions\\";
			lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}
	}
#else // Some other platform, like Linux
    TTFoundationLoadExternalClassesFromFolder("/usr/local/lib/jamoma/extensions");
#endif
}

void TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath)
{
#if defined(TT_PLATFORM_MAC) || defined(TT_PLATFORM_LINUX) || defined(TT_PLATFORM_WIN)
 	TTExtensionInitializationMethod	initializer;
	TTString						initializerFunctionName;
	TTErr							err;
	TTPath							path(fullpath);
	TTString						extensionFilename;
	TTString						extensionFileExtension;
    TTPathVector					paths;
    TTPathIter						i;

	err = path.getDirectoryListing(paths);
    if (!err) {
        for (i = paths.begin(); i != paths.end(); ++i) {
            TTPath							aPath = *i;
            TTString						aPathString;
            void*							handle = NULL;

            aPath.getString(aPathString);
            cout << "EXTENSION: " << aPathString << endl;

			// make sure the files have the correct extension before trying to load them
			aPath.getExtension(extensionFileExtension);
#ifdef TT_PLATFORM_LINUX
			if (extensionFileExtension != ".ttso")
#elif defined(TT_PLATFORM_MAC)
			if (extensionFileExtension != ".ttdylib")
#elif defined(TT_PLATFORM_WIN)
			if (extensionFileExtension != ".ttdll")
#endif
				continue;

#ifdef TT_PLATFORM_WIN
			handle = LoadLibrary(aPathString.c_str());
#else
            handle = dlopen(aPathString.c_str(), RTLD_LAZY);
#endif
            cout << "HANDLE: " << handle << endl;
            if (!handle)
                continue;

            // TODO: assert -- or at least do a log post -- if handle is NULL
			aPath.getStem(extensionFilename);
			initializerFunctionName = "TTLoadJamomaExtension_";
			initializerFunctionName += extensionFilename;
#ifdef TT_PLATFORM_WIN
			initializer = (TTExtensionInitializationMethod)GetProcAddress((HMODULE)handle, initializerFunctionName.c_str());
#else
            initializer = (TTExtensionInitializationMethod)dlsym(handle, initializerFunctionName.c_str());
#endif
            if (initializer)
                err = initializer();
        }
    }
#endif
// No dynamic loading on iOS
}

<commit_msg>TTFoundationInit() now loads only extensions from a standalone when extensions in a standalone are present.  Fixes #348.<commit_after>/*
 * Jamoma Foundation
 * Copyright © 2008, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTFoundation.h"
#include "TTSymbolTable.h"
#include "TTEnvironment.h"
#include "TTSymbolCache.h"
#include "TTValueCache.h"
#include "TTCallback.h"
#include "TTNode.h"
#include "TTNodeDirectory.h"
#include "TTPath.h"

// Unit Tests
#include "TTMatrix.h"
#include "TTMatrixArray.h"
#include "TTValue.test.h"

#ifdef TT_PLATFORM_MAC
#include <dlfcn.h>
#elif TT_PLATFORM_LINUX
#include <dlfcn.h>
#elif TT_PLATFORM_WIN
#include <ShlObj.h>
#endif

static bool		TTFoundationHasInitialized = false;
static TTString	TTFoundationBinaryPath = "";

void		TTFoundationLoadExternalClasses();
TTErr		TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath);
TTObjectPtr	TTFoundationInstantiateInternalClass(TTSymbol* className, TTValue& arguments);

/****************************************************************************************************/
void TTFoundationInit(const char* pathToBinaries)
{
	if (!TTFoundationHasInitialized) {
		TTFoundationHasInitialized = true;

		if (pathToBinaries)
			TTFoundationBinaryPath = pathToBinaries;

		ttSymbolTable = new TTSymbolTable;
		for (int i=0; i<kNumTTDataTypes; i++)
			TTDataInfo::addDataInfoForType(TTDataType(i));

		ttEnvironment = new TTEnvironment;

		TTSymbolCacheInit();
		TTValueCacheInit();

#ifdef TT_DEBUG
		TTLogMessage("JamomaFoundation (TT_DEBUG) -- Version %s", TTFOUNDATION_VERSION_STRING);
		ttEnvironment->mDebugBasic = true;
#else
		TTLogMessage("JamomaFoundation -- Version %s", TTFOUNDATION_VERSION_STRING);
#endif
		if (pathToBinaries)
			TTLogMessage("-- Path %s\n", pathToBinaries);
		else
			TTLogMessage("\n");

		// register classes -- both internal and external
		TTCallback::registerClass();
		TTMatrix::registerClass();
		TTMatrixArray::registerClass();
		TTValueTest::registerClass();

		TTFoundationLoadExternalClasses();
	}
}

void TTFoundationShutdown()
{
	// FIXME: How do we call this (i.e. TTDSPShutdown()?) -- do we need to setup an observer of some sort on the environment class?
	// TODO: we need to free singletons like the environment here!
}

/****************************************************************************************************/

void TTFoundationLoadExternalClasses()
{
#ifdef TT_PLATFORM_MAC
	if (!TTFoundationBinaryPath.empty()) {
		// Look in the specified folder rather than the default location
		TTString extensionsPath = TTFoundationBinaryPath + "/Extensions";
		TTFoundationLoadExternalClassesFromFolder(extensionsPath);
	}
	else {
		OSErr		err = noErr;
		FSRef		ref;
		UInt8		path[4096];
		TTString	fullpath;

		// Look in the folder of the host application
		CFBundleRef mainBundle = CFBundleGetMainBundle();
		CFURLRef	mainBundleURL = CFBundleCopyBundleURL(mainBundle);
		CFStringRef mainBundlePath = CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
		char		mainBundleStr[4096];

		CFStringGetCString(mainBundlePath, mainBundleStr, 4096, kCFStringEncodingUTF8);
		strncat(mainBundleStr, "/Contents/Jamoma/Extensions", 4096);
		mainBundleStr[4095] = 0;
		err = TTFoundationLoadExternalClassesFromFolder(mainBundleStr);
		if (!err)
			return; // if we loaded classes out of a standalone app, then we don't want to be corrupted by global extensions Redmine #348
					// it could be that you want to create a standalone with a plug-in architecture -- for now that problem is ignored.

		// Look in ~/Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}

		// Look in /Library/Application Support/Jamoma/Extensions
		err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
		if (!err) {
			FSRefMakePath(&ref, path, 4096);
			fullpath = (char*)path;
			fullpath += "/Jamoma/Extensions";
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}

	}
#elif TT_PLATFORM_WIN
	TTString	fullpath;
	char		temppath[4096];
	HKEY		hKey = 0;
	LONG		lRes;
	DWORD		dwSize = sizeof(temppath);
	HRESULT		hr;
	HINSTANCE	hInstance = GetModuleHandle(NULL);

	// Look in C:\Program Files\Common Files\TTBlue\Extensions
	hr = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_CURRENT, (LPSTR)temppath);
	if (!FAILED(hr)) {
		fullpath = temppath;
		fullpath += "\\Jamoma\\Extensions\\";
		lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
		TTFoundationLoadExternalClassesFromFolder(fullpath);
	}

	// TODO: Look in some user-level directory like we do on the Mac?

	// Look in the support folder of the host application
	if (hInstance) {
		GetModuleFileName(hInstance, (LPSTR)temppath, 4096);
		if (temppath[0]) {
			char *s = strrchr(temppath, '\\');
			if (s)
				*s = 0;
			fullpath = temppath;
			fullpath += "\\Jamoma\\Extensions\\";
			lRes = SHCreateDirectory(NULL, (LPCWSTR)fullpath.c_str());
			TTFoundationLoadExternalClassesFromFolder(fullpath);
		}
	}
#else // Some other platform, like Linux
    TTFoundationLoadExternalClassesFromFolder("/usr/local/lib/jamoma/extensions");
#endif
}

TTErr TTFoundationLoadExternalClassesFromFolder(const TTString& fullpath)
{
#if defined(TT_PLATFORM_MAC) || defined(TT_PLATFORM_LINUX) || defined(TT_PLATFORM_WIN)
 	TTExtensionInitializationMethod	initializer;
	TTString						initializerFunctionName;
	TTErr							err;
	TTPath							path(fullpath);
	TTString						extensionFilename;
	TTString						extensionFileExtension;
    TTPathVector					paths;
    TTPathIter						i;

	err = path.getDirectoryListing(paths);
    if (!err) {
        for (i = paths.begin(); i != paths.end(); ++i) {
            TTPath							aPath = *i;
            TTString						aPathString;
            void*							handle = NULL;

            aPath.getString(aPathString);
            cout << "EXTENSION: " << aPathString << endl;

			// make sure the files have the correct extension before trying to load them
			aPath.getExtension(extensionFileExtension);
#ifdef TT_PLATFORM_LINUX
			if (extensionFileExtension != ".ttso")
#elif defined(TT_PLATFORM_MAC)
			if (extensionFileExtension != ".ttdylib")
#elif defined(TT_PLATFORM_WIN)
			if (extensionFileExtension != ".ttdll")
#endif
				continue;

#ifdef TT_PLATFORM_WIN
			handle = LoadLibrary(aPathString.c_str());
#else
            handle = dlopen(aPathString.c_str(), RTLD_LAZY);
#endif
            cout << "HANDLE: " << handle << endl;
            if (!handle)
                continue;

            // TODO: assert -- or at least do a log post -- if handle is NULL
			aPath.getStem(extensionFilename);
			initializerFunctionName = "TTLoadJamomaExtension_";
			initializerFunctionName += extensionFilename;
#ifdef TT_PLATFORM_WIN
			initializer = (TTExtensionInitializationMethod)GetProcAddress((HMODULE)handle, initializerFunctionName.c_str());
#else
            initializer = (TTExtensionInitializationMethod)dlsym(handle, initializerFunctionName.c_str());
#endif
            if (initializer)
                err = initializer();
        }
    }
	else
		return err;
#endif
// No dynamic loading on iOS
	return kTTErrNone;
}

<|endoftext|>


<commit_before>#include "wwidget.h"
#include <QQmlEngine>
#include <QQuickItem>
#include <QDir>

WWidget::WWidget(const QUrl fileurl, const QString filepath) : QQuickView(fileurl)
{
    // Store the widget's qml file url and path.`
    this->fileurl = fileurl;
    this->filepath = filepath;
    this->setParent(Q_NULLPTR);

    // Transparent and Frameless Window:
    this->setFlags(this->normalFlags);
    this->setColor(QColor(0,0,0,0));

    // Show:
    this->show();

    // Widget's RightClick Menu
    addRightClickMenu();
}

void WWidget::reload(){
    this->setSource(QUrl());
    this->engine()->clearComponentCache();
    this->setSource(fileurl);
}

// Drag&Drop the widget: (This prevents qml's onClick events.)
void WWidget::mousePressEvent(QMouseEvent *event){
    switch (event->button()) {
    case (Qt::LeftButton): {
        isDragging = true;
        dragX = event->x();
        dragY = event->y();
        break;
    }
    case (Qt::RightButton): {
        QPoint pt(event->pos());
        pt.setX(pt.x()+4);
        pt.setY(pt.y()+20);
        menu_rightClick->exec( this->mapToGlobal(pt) );
        break;
    }
    default:
        break;
    }

}
void WWidget::mouseMoveEvent(QMouseEvent *event){
    if(isDragging)
        this->setPosition(event->globalX() - dragX, event->globalY() - dragY);
}
void WWidget::mouseReleaseEvent(QMouseEvent *event){
    Q_UNUSED(event)
    isDragging = false;
}

void WWidget::addRightClickMenu(){
    // Menu
    menu_rightClick = new QMenu();
    menu_rightClick->setContextMenuPolicy(Qt::CustomContextMenu);
    act_seperator = new QAction(this);
    act_seperator->setSeparator(true);

    // Groups (for Radio Button effect)
    QActionGroup* actgr_zPositionGroup = new QActionGroup( this );

    // MENU ACTIONS -->>
    // -- Hide
    QAction* act_Hide = new QAction("Hide",this);
    connect(act_Hide, &QAction::triggered, [=]{
        this->close();
        this->destroy();
        delete this;
    });
    // -- {SEPERATOR_AT_HERE}
    // -- Always on Most Top
    QAction* act_alwaysOnMostTop = new QAction("Always on Most top",this);
    act_alwaysOnMostTop->setCheckable(true);
    act_alwaysOnMostTop->setActionGroup( actgr_zPositionGroup );
    connect(act_alwaysOnMostTop, &QAction::triggered, [=]{
        if(act_alwaysOnMostTop->isChecked()){
            if(this->latestFlags == this->alwaysMostTopFlags){
                this->destroy();
                this->create();
                this->show();
                this->setFlags(this->normalFlags | this->alwaysMostTopFlags);
                qDebug() << "Bi resetlendi.";
            }else{
                this->hide();
                this->setFlags((this->flags() ^ this->latestFlags) | this->alwaysMostTopFlags);
                this->show();
                qDebug() << this->flags();
                this->requestActivate();
            }

            this->latestFlags = this->alwaysMostTopFlags;
        }
    });
    // -- Always on top
    QAction* act_alwaysOnTop = new QAction("Always on top",this);
    act_alwaysOnTop->setCheckable(true);
    act_alwaysOnTop->setActionGroup( actgr_zPositionGroup );
    connect(act_alwaysOnTop, &QAction::triggered, [=]{
        if(act_alwaysOnTop->isChecked()){
            if(this->latestFlags == this->alwaysMostTopFlags){
                this->destroy();
                this->create();
                this->show();
                this->setFlags(this->normalFlags);
                this->setFlags(this->flags() | this->alwaysTopFlags);
            }else{
                this->setFlags((this->flags() ^ this->latestFlags) | this->alwaysTopFlags);
                this->show();
            }

            this->latestFlags = this->alwaysTopFlags;
        }
    });
    // -- Normal (DEFAULT)
    QAction* act_normal = new QAction("Normal",this);
    act_normal->setCheckable(true);
    act_normal->setActionGroup( actgr_zPositionGroup );
    act_normal->setChecked(true);
    connect(act_normal, &QAction::triggered, [=]{
        if(this->latestFlags == this->alwaysMostTopFlags){
            this->destroy();
            this->create();
            this->show();
            this->setFlags(this->normalFlags);
        }else{
            this->setFlags((this->flags() ^ this->latestFlags));
            this->show();
        }

        this->latestFlags = Q_NULLPTR;
    });
    // -- Always on bottom
    QAction* act_alwaysOnBottom = new QAction("Always on bottom",this);
    act_alwaysOnBottom->setCheckable(true);
    act_alwaysOnBottom->setActionGroup( actgr_zPositionGroup );
    connect(act_alwaysOnBottom, &QAction::triggered, [=]{
        if(act_alwaysOnBottom->isChecked()){
            if(this->latestFlags == this->alwaysMostTopFlags){
                this->destroy();
                this->create();
                this->show();
                this->setFlags(this->normalFlags | this->alwaysBottomFlags);
            }else{
                this->setFlags((this->flags() ^ this->latestFlags) | this->alwaysBottomFlags);
                this->show();
            }

            this->latestFlags = this->alwaysBottomFlags;
        }
    });

    // Adding Sub-Menus & Actions
    menu_rightClick->addAction(act_Hide);
    menu_rightClick->addAction(act_seperator);
    QMenu* submenu_zindex = menu_rightClick->addMenu("Z-Position");
        submenu_zindex->addAction(act_alwaysOnMostTop);
        submenu_zindex->addAction(act_alwaysOnTop);
        submenu_zindex->addAction(act_normal);
        submenu_zindex->addAction(act_alwaysOnBottom);

}

<commit_msg>[Added] Reloading the widget from right click.<commit_after>#include "wwidget.h"
#include <QQmlEngine>
#include <QQuickItem>
#include <QDir>

WWidget::WWidget(const QUrl fileurl, const QString filepath) : QQuickView(fileurl)
{
    // Store the widget's qml file url and path.`
    this->fileurl = fileurl;
    this->filepath = filepath;
    this->setParent(Q_NULLPTR);

    // Transparent and Frameless Window:
    this->setFlags(this->normalFlags);
    this->setColor(QColor(0,0,0,0));

    // Show:
    this->show();

    // Widget's RightClick Menu
    addRightClickMenu();
}

void WWidget::reload(){
    this->setSource(QUrl());
    this->engine()->clearComponentCache();
    this->setSource(fileurl);
}

// Drag&Drop the widget: (This prevents qml's onClick events.)
void WWidget::mousePressEvent(QMouseEvent *event){
    switch (event->button()) {
    case (Qt::LeftButton): {
        isDragging = true;
        dragX = event->x();
        dragY = event->y();
        break;
    }
    case (Qt::RightButton): {
        QPoint pt(event->pos());
        pt.setX(pt.x()+4);
        pt.setY(pt.y()+20);
        menu_rightClick->exec( this->mapToGlobal(pt) );
        break;
    }
    default:
        break;
    }

}
void WWidget::mouseMoveEvent(QMouseEvent *event){
    if(isDragging)
        this->setPosition(event->globalX() - dragX, event->globalY() - dragY);
}
void WWidget::mouseReleaseEvent(QMouseEvent *event){
    Q_UNUSED(event)
    isDragging = false;
}

void WWidget::addRightClickMenu(){
    // Menu
    menu_rightClick = new QMenu();
    menu_rightClick->setContextMenuPolicy(Qt::CustomContextMenu);
    act_seperator = new QAction(this);
    act_seperator->setSeparator(true);

    // Groups (for Radio Button effect)
    QActionGroup* actgr_zPositionGroup = new QActionGroup( this );

    // MENU ACTIONS -->>
    // -- Hide
    QAction* act_Hide = new QAction("Hide",this);
    connect(act_Hide, &QAction::triggered, [=]{
        this->close();
        this->destroy();
        delete this;
    });
    // -- Reload
    QAction* act_Reload = new QAction("Reload",this);
    connect(act_Reload, &QAction::triggered, [=]{
        this->reload();
    });
    // -- {SEPERATOR_AT_HERE}
    // -- Always on Most Top
    QAction* act_alwaysOnMostTop = new QAction("Always on Most top",this);
    act_alwaysOnMostTop->setCheckable(true);
    act_alwaysOnMostTop->setActionGroup( actgr_zPositionGroup );
    connect(act_alwaysOnMostTop, &QAction::triggered, [=]{
        if(act_alwaysOnMostTop->isChecked()){
            if(this->latestFlags == this->alwaysMostTopFlags){
                this->destroy();
                this->create();
                this->show();
                this->setFlags(this->normalFlags | this->alwaysMostTopFlags);
                qDebug() << "Bi resetlendi.";
            }else{
                this->hide();
                this->setFlags((this->flags() ^ this->latestFlags) | this->alwaysMostTopFlags);
                this->show();
                qDebug() << this->flags();
                this->requestActivate();
            }

            this->latestFlags = this->alwaysMostTopFlags;
        }
    });
    // -- Always on top
    QAction* act_alwaysOnTop = new QAction("Always on top",this);
    act_alwaysOnTop->setCheckable(true);
    act_alwaysOnTop->setActionGroup( actgr_zPositionGroup );
    connect(act_alwaysOnTop, &QAction::triggered, [=]{
        if(act_alwaysOnTop->isChecked()){
            if(this->latestFlags == this->alwaysMostTopFlags){
                this->destroy();
                this->create();
                this->show();
                this->setFlags(this->normalFlags);
                this->setFlags(this->flags() | this->alwaysTopFlags);
            }else{
                this->setFlags((this->flags() ^ this->latestFlags) | this->alwaysTopFlags);
                this->show();
            }

            this->latestFlags = this->alwaysTopFlags;
        }
    });
    // -- Normal (DEFAULT)
    QAction* act_normal = new QAction("Normal",this);
    act_normal->setCheckable(true);
    act_normal->setActionGroup( actgr_zPositionGroup );
    act_normal->setChecked(true);
    connect(act_normal, &QAction::triggered, [=]{
        if(this->latestFlags == this->alwaysMostTopFlags){
            this->destroy();
            this->create();
            this->show();
            this->setFlags(this->normalFlags);
        }else{
            this->setFlags((this->flags() ^ this->latestFlags));
            this->show();
        }

        this->latestFlags = Q_NULLPTR;
    });
    // -- Always on bottom
    QAction* act_alwaysOnBottom = new QAction("Always on bottom",this);
    act_alwaysOnBottom->setCheckable(true);
    act_alwaysOnBottom->setActionGroup( actgr_zPositionGroup );
    connect(act_alwaysOnBottom, &QAction::triggered, [=]{
        if(act_alwaysOnBottom->isChecked()){
            if(this->latestFlags == this->alwaysMostTopFlags){
                this->destroy();
                this->create();
                this->show();
                this->setFlags(this->normalFlags | this->alwaysBottomFlags);
            }else{
                this->setFlags((this->flags() ^ this->latestFlags) | this->alwaysBottomFlags);
                this->show();
            }

            this->latestFlags = this->alwaysBottomFlags;
        }
    });

    // Adding Sub-Menus & Actions
    menu_rightClick->addAction(act_Hide);
    menu_rightClick->addAction(act_Reload);
    menu_rightClick->addAction(act_seperator);
    QMenu* submenu_zindex = menu_rightClick->addMenu("Z-Position");
        submenu_zindex->addAction(act_alwaysOnMostTop);
        submenu_zindex->addAction(act_alwaysOnTop);
        submenu_zindex->addAction(act_normal);
        submenu_zindex->addAction(act_alwaysOnBottom);

}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <windows.h>
#include <Dbt.h>
#include <ShlObj.h>

#include "pfs.h"

#define SZSERVICENAME          L"pfs"
#define SZSERVICEDISPLAYNAME   L"PCloud File System"
#define DOKAN_DLL              L"dokan.dll"

#define REGISTRY_KEY_PCLOUD    L"SOFTWARE\\PCloud\\pfs"

#define KEY_USER               "username"
#define KEY_PASS               "pass"
#define KEY_AUTH               "auth"
#define KEY_DELETE             "del"

DWORD                   dwErr = 0;
BOOL                    bStop = FALSE;
SERVICE_STATUS_HANDLE   sshStatusHandle;
SERVICE_STATUS          ssStatus;

typedef BOOL (__stdcall *DokanUnmountType)(WCHAR DriveLetter);

BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;
    BOOL fResult = TRUE;

    if (dwCurrentState == SERVICE_START_PENDING)
        ssStatus.dwControlsAccepted = 0;
    else
        ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

    ssStatus.dwCurrentState = dwCurrentState;
    ssStatus.dwWin32ExitCode = dwWin32ExitCode;
    ssStatus.dwWaitHint = dwWaitHint;

    if (( dwCurrentState == SERVICE_RUNNING ) ||
        ( dwCurrentState == SERVICE_STOPPED ))
        ssStatus.dwCheckPoint = 0;
    else
        ssStatus.dwCheckPoint = dwCheckPoint++;
    fResult = SetServiceStatus(sshStatusHandle, &ssStatus);
    return fResult;
}

static char getFirstFreeDevice()
{
    DWORD devices = GetLogicalDrives();
    for (int i = 4; i < 32; ++i)
        if ((devices & (1<<i))==0)
            return i + 'A';
    return 0;
}

static void storeKey(LPCSTR key, const char * val)
{
    HRESULT hr;
    HKEY hKey;
    hr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, NULL, 0,
                        KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if (!hr)
    {
        hr = RegSetValueExA(hKey, key, 0, REG_SZ, (LPBYTE)val, strlen(val)+1);
        RegCloseKey(hKey);
    }
}

static void getDataFromRegistry(const char* key, char data[MAX_PATH])
{
    HRESULT hr;
    char buffer[MAX_PATH];
    DWORD cbDataSize = sizeof(buffer);
    HKEY hKey;
    hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, KEY_READ, &hKey);
    if (hr)
    {
        storeKey(key, "");
        hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, KEY_READ, &hKey);
    }
    if (!hr)
    {
        hr = RegQueryValueExA(hKey, key, NULL, NULL, (LPBYTE)data, &cbDataSize);
        RegCloseKey(hKey);
    }
}

char mountPoint[3] = "a:";

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
    char username[MAX_PATH]="";
    char password[MAX_PATH]="";
    char* params[2] = {(char *)"pfs", mountPoint};

    mountPoint[0] = getFirstFreeDevice();
    getDataFromRegistry(KEY_USER, username);
    debug("user:%s\n", username);
    getDataFromRegistry(KEY_PASS, password);
    debug("pass:%s\n", password);

    return pfs_main(2, params, username, password);
}

VOID WINAPI ServiceStart(const wchar_t * config_file)
{
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    debug("Thread created\n");
    int loop = 0;
    ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
    while (!bStop)
    {
        Sleep(500);
        if (loop % 10 == 0)
        {
            DWORD recipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
            DEV_BROADCAST_VOLUME msg;
            ZeroMemory(&msg, sizeof(msg));
            msg.dbcv_size = sizeof(msg);
            msg.dbcv_devicetype = DBT_DEVTYP_VOLUME;
            msg.dbcv_unitmask = 1 << (mountPoint[0] - 'A');
            BroadcastSystemMessage(0, &recipients, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&msg);
            loop = 0;
        }
        ++loop;
    }
    ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);

    debug("Service main - waiting\n");
    WaitForSingleObject(hThread, 5000);

    debug("Service main - closing\n");
    CloseHandle(hThread);

    ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);

    debug("Service main - exit\n");
}

VOID WINAPI ServiceStop()
{
    debug("ServiceStop\n");
    DokanUnmountType Unmount = NULL;
    HMODULE dokanDll = LoadLibraryW(DOKAN_DLL);
    if (dokanDll) Unmount=(DokanUnmountType)GetProcAddress(dokanDll, "DokanUnmount");

    bStop=TRUE;
    if (mountPoint[0] != 'a' && Unmount)
    {
        debug("Unmounting...\n");
        Unmount((WCHAR)mountPoint[0]);
    }
    if (dokanDll) FreeLibrary(dokanDll);
}

VOID WINAPI service_ctrl(DWORD dwCtrlCode)
{
    switch(dwCtrlCode)
    {
        case SERVICE_CONTROL_STOP:
            storeKey(KEY_DELETE, "+");
            debug("SERVICE_CONTROL_STOP \n");
            ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
            ServiceStop();
            return;
        case SERVICE_CONTROL_SHUTDOWN:
            debug("SERVICE_CONTROL_SHUTDOWN \n");
            ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 2000);
            ServiceStop();
            return;
        default:
            break;
    }
    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}

void CmdInstallService(BOOL Start)
{
    SC_HANDLE       schService = NULL;
    SC_HANDLE       schSCManager = NULL;

    TCHAR szPath[512];

    if (GetModuleFileName(NULL, szPath, 512) == 0)
    {
        printf( "Unable to install %S\n", SZSERVICEDISPLAYNAME);
        return;
    }

    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (schSCManager)
    {
        schService = CreateService(schSCManager, SZSERVICENAME, SZSERVICEDISPLAYNAME,
            SERVICE_ALL_ACCESS,
            SERVICE_WIN32_OWN_PROCESS  | SERVICE_INTERACTIVE_PROCESS,
            SERVICE_AUTO_START,
            SERVICE_ERROR_NORMAL,
            szPath, NULL, NULL, NULL, NULL, NULL);

        if (schService)
        {
            printf("%S installed.\n", SZSERVICEDISPLAYNAME);
        } else
        {
            printf("CreateService failed %lu!\n", GetLastError());
            return;
        }
    } else
    {
        printf("OpenSCManager failed!\n");
        return;
    }

    if (Start && StartService(schService, 0, NULL))
    {
        printf("Starting %S.\n", SZSERVICEDISPLAYNAME);
        Sleep(1000);
        while (QueryServiceStatus(schService, &ssStatus))
        {
            if (ssStatus.dwCurrentState == SERVICE_START_PENDING)
                Sleep(1000);
            else
                break;
        }

        if (ssStatus.dwCurrentState == SERVICE_RUNNING)
        {
            printf("\n%S started.\n", SZSERVICEDISPLAYNAME);
        } else
        {
            printf("\n%S failed to start.\n", SZSERVICEDISPLAYNAME);
        }
    }
    else
    {
        if (Start) printf("\n%S failed to start.\n", SZSERVICEDISPLAYNAME);
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}

void CmdRemoveService()
{
    SC_HANDLE       schService;
    SC_HANDLE       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (schSCManager)
    {
        schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
        if (schService)
        {
            ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus);

            printf("Stopping %S.\n", SZSERVICEDISPLAYNAME);
            int retry = 5;

            while(QueryServiceStatus(schService, &ssStatus) && retry)
            {
                if (ssStatus.dwCurrentState == SERVICE_STOPPED)
                    break;
                if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
                    Sleep(1000);
                else
                {
                    printf("Stopping service - status %lu?\n", ssStatus.dwCurrentState);
                    Sleep(1000);
                    --retry;
                }
            }
            if (ssStatus.dwCurrentState == SERVICE_STOPPED)
            {
                printf("\n%S stopped.\n", SZSERVICEDISPLAYNAME);
            }else
            {
                printf("\n%S failed to stop.\n", SZSERVICEDISPLAYNAME);
            }

            if(DeleteService(schService))
            {
                printf("%S removed.\n", SZSERVICEDISPLAYNAME);
            } else
            {
                printf("DeleteService failed %u!\n", (UINT32)GetLastError());
            }
            CloseServiceHandle(schService);
        }
        else
        {
            printf("OpenService failed!\n");
        }
        CloseServiceHandle(schSCManager);
    }
    else
    {
        printf("OpenSCManager failed!\n");
    }
}

VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
{
    debug("Called service main %d .\n", bStop);

    if (bStop) return;

    sshStatusHandle = RegisterServiceCtrlHandler(SZSERVICENAME, service_ctrl);
    if (sshStatusHandle)
    {
        ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
        ssStatus.dwServiceSpecificExitCode = 0;

        if (ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
            ServiceStart(NULL);

        ReportStatusToSCMgr(SERVICE_STOPPED, dwErr, 0);
    }
}

int main(int argc, char* args[])
{
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        {(wchar_t*)SZSERVICENAME, (LPSERVICE_MAIN_FUNCTION)service_main},
        {NULL, NULL}
    };

    if (argc > 1)
    {
        if (((args[1][0] == '-') || (args[1][0] == '/')))
        {
            if (!strcmp("install", args[1]+1))
            {
                bStop = FALSE;
                CmdInstallService(argc > 2);
                return 0;
            }
            else if (!strcmp("remove", args[1]+1))
            {
                bStop = TRUE;
                CmdRemoveService();
                return 0;
            }
            else
            {
                goto dispatch;
            }
        }
    }
    else
    {
        SC_HANDLE       schService = NULL;
        SC_HANDLE       schSCManager = NULL;
        SERVICE_STATUS  ssStatus;
        char buff[8];

        getDataFromRegistry(KEY_DELETE, buff);
        if (buff[0] == '+')
        {
            debug ("Called main while service is stopping!\n");
            storeKey(KEY_DELETE, "");
            return 1;
        }

        StartServiceCtrlDispatcher(dispatchTable);
        schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if (schSCManager)
        {
            schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
            if (schService)
            {
                debug("called main function - no args\n");
                QueryServiceStatus(schService, &ssStatus);
                if (ssStatus.dwCurrentState != SERVICE_STOPPED)
                {
                    debug("called main function - status %lu\n", ssStatus.dwCurrentState);
                    return 1;
                }
                if (StartService(schService, 0, NULL))
                {
                    printf("Starting %S.\n", SZSERVICEDISPLAYNAME);
                    Sleep(1000);
                    int retry = 5;
                    while(QueryServiceStatus(schService, &ssStatus) && retry)
                    {
                        --retry;
                        if (ssStatus.dwCurrentState == SERVICE_START_PENDING)
                            Sleep(1000);
                        else
                            break;
                    }
                    if (ssStatus.dwCurrentState == SERVICE_RUNNING)
                    {
                        printf("\n%S started.\n", SZSERVICENAME);
                    }
                    else
                    {
                        printf("\n%S failed to start.\n", SZSERVICENAME);
                    }
                }
                else
                {
                    printf("\nFailed to start %S.\n", SZSERVICENAME);
                }
                CloseServiceHandle(schService);
            }
            else
            {
                printf("Failed to load the service... \n");
                return 1;
            }
        }

        CloseServiceHandle(schSCManager);
        return 0;
    }

dispatch:
    printf("Usage\n"
           "  -install\t\tinstall the service\n"
           "  -remove \t\tremove the service\n");
    return 1;
}
<commit_msg>Added notification to the UI (not working actually)<commit_after>#include <stdio.h>
#include <windows.h>
#include <Dbt.h>
#include <ShlObj.h>

#include "pfs.h"

#define SZSERVICENAME          L"pfs"
#define SZSERVICEDISPLAYNAME   L"PCloud File System"
#define DOKAN_DLL              L"dokan.dll"

#define REGISTRY_KEY_PCLOUD    L"SOFTWARE\\PCloud\\pfs"

#define KEY_USER               "username"
#define KEY_PASS               "pass"
#define KEY_AUTH               "auth"
#define KEY_DELETE             "del"

#ifndef ENOTCONN
#   define ENOTCONN        107
#endif

#ifndef EACCES
#define EACCES 13
#endif
DWORD                   dwErr = 0;
BOOL                    bStop = FALSE;
SERVICE_STATUS_HANDLE   sshStatusHandle;
SERVICE_STATUS          ssStatus;

typedef BOOL (__stdcall *DokanUnmountType)(WCHAR DriveLetter);

BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;
    BOOL fResult = TRUE;

    if (dwCurrentState == SERVICE_START_PENDING)
        ssStatus.dwControlsAccepted = 0;
    else
        ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

    ssStatus.dwCurrentState = dwCurrentState;
    ssStatus.dwWin32ExitCode = dwWin32ExitCode;
    ssStatus.dwWaitHint = dwWaitHint;

    if (( dwCurrentState == SERVICE_RUNNING ) ||
        ( dwCurrentState == SERVICE_STOPPED ))
        ssStatus.dwCheckPoint = 0;
    else
        ssStatus.dwCheckPoint = dwCheckPoint++;
    fResult = SetServiceStatus(sshStatusHandle, &ssStatus);
    return fResult;
}

static char getFirstFreeDevice()
{
    DWORD devices = GetLogicalDrives();
    for (int i = 4; i < 32; ++i)
        if ((devices & (1<<i))==0)
            return i + 'A';
    return 0;
}

static void storeKey(LPCSTR key, const char * val)
{
    HRESULT hr;
    HKEY hKey;
    hr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, NULL, 0,
                        KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if (!hr)
    {
        hr = RegSetValueExA(hKey, key, 0, REG_SZ, (LPBYTE)val, strlen(val)+1);
        RegCloseKey(hKey);
    }
}

static void getDataFromRegistry(const char* key, char data[MAX_PATH])
{
    HRESULT hr;
    char buffer[MAX_PATH];
    DWORD cbDataSize = sizeof(buffer);
    HKEY hKey;
    hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, KEY_READ, &hKey);
    if (hr)
    {
        storeKey(key, "");
        hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY_PCLOUD, 0, KEY_READ, &hKey);
    }
    if (!hr)
    {
        hr = RegQueryValueExA(hKey, key, NULL, NULL, (LPBYTE)data, &cbDataSize);
        RegCloseKey(hKey);
    }
}

char mountPoint[3] = "a:";

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
    char username[MAX_PATH]="";
    char password[MAX_PATH]="";
    char* params[2] = {(char *)"pfs", mountPoint};

    mountPoint[0] = getFirstFreeDevice();
    getDataFromRegistry(KEY_USER, username);
    debug("user:%s\n", username);
    getDataFromRegistry(KEY_PASS, password);
    debug("pass:%s\n", password);

    int res = pfs_main(2, params, username, password);
    if (res == ENOTCONN)
    {
        SendMessageTimeout(HWND_BROADCAST, WM_USER+876, 0, 1, SMTO_BLOCK, 2000, NULL);
        debug("Send NotConnected msg\n");
    }
    else if (res == EACCES)
    {
        SendMessageTimeout(HWND_BROADCAST, WM_USER+876, 0, 2, SMTO_BLOCK, 2000, NULL);
        debug("Send Access denied msg\n");
    }
    return res;
}

VOID WINAPI ServiceStart(const wchar_t * config_file)
{
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    debug("Thread created\n");
    int loop = 0;
    ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
    while (!bStop)
    {
        Sleep(500);
        if (loop % 10 == 0)
        {
            DWORD recipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
            DEV_BROADCAST_VOLUME msg;
            ZeroMemory(&msg, sizeof(msg));
            msg.dbcv_size = sizeof(msg);
            msg.dbcv_devicetype = DBT_DEVTYP_VOLUME;
            msg.dbcv_unitmask = 1 << (mountPoint[0] - 'A');
            BroadcastSystemMessage(0, &recipients, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&msg);
            loop = 0;
        }
        ++loop;
    }
    ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);

    debug("Service main - waiting\n");
    WaitForSingleObject(hThread, 5000);

    debug("Service main - closing\n");
    CloseHandle(hThread);

    ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);

    debug("Service main - exit\n");
}

VOID WINAPI ServiceStop()
{
    debug("ServiceStop\n");
    DokanUnmountType Unmount = NULL;
    HMODULE dokanDll = LoadLibraryW(DOKAN_DLL);
    if (dokanDll) Unmount=(DokanUnmountType)GetProcAddress(dokanDll, "DokanUnmount");

    bStop=TRUE;
    if (mountPoint[0] != 'a' && Unmount)
    {
        debug("Unmounting...\n");
        Unmount((WCHAR)mountPoint[0]);
    }
    if (dokanDll) FreeLibrary(dokanDll);
}

VOID WINAPI service_ctrl(DWORD dwCtrlCode)
{
    switch(dwCtrlCode)
    {
        case SERVICE_CONTROL_STOP:
            storeKey(KEY_DELETE, "+");
            debug("SERVICE_CONTROL_STOP \n");
            ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
            ServiceStop();
            return;
        case SERVICE_CONTROL_SHUTDOWN:
            debug("SERVICE_CONTROL_SHUTDOWN \n");
            ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 2000);
            ServiceStop();
            return;
        default:
            break;
    }
    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}

void CmdInstallService(BOOL Start)
{
    SC_HANDLE       schService = NULL;
    SC_HANDLE       schSCManager = NULL;

    TCHAR szPath[512];

    if (GetModuleFileName(NULL, szPath, 512) == 0)
    {
        printf( "Unable to install %S\n", SZSERVICEDISPLAYNAME);
        return;
    }

    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (schSCManager)
    {
        schService = CreateService(schSCManager, SZSERVICENAME, SZSERVICEDISPLAYNAME,
            SERVICE_ALL_ACCESS,
            SERVICE_WIN32_OWN_PROCESS  | SERVICE_INTERACTIVE_PROCESS,
            SERVICE_AUTO_START,
            SERVICE_ERROR_NORMAL,
            szPath, NULL, NULL, NULL, NULL, NULL);

        if (schService)
        {
            printf("%S installed.\n", SZSERVICEDISPLAYNAME);
        } else
        {
            printf("CreateService failed %lu!\n", GetLastError());
            return;
        }
    } else
    {
        printf("OpenSCManager failed!\n");
        return;
    }

    if (Start && StartService(schService, 0, NULL))
    {
        printf("Starting %S.\n", SZSERVICEDISPLAYNAME);
        Sleep(1000);
        while (QueryServiceStatus(schService, &ssStatus))
        {
            if (ssStatus.dwCurrentState == SERVICE_START_PENDING)
                Sleep(1000);
            else
                break;
        }

        if (ssStatus.dwCurrentState == SERVICE_RUNNING)
        {
            printf("\n%S started.\n", SZSERVICEDISPLAYNAME);
        } else
        {
            printf("\n%S failed to start.\n", SZSERVICEDISPLAYNAME);
        }
    }
    else
    {
        if (Start) printf("\n%S failed to start.\n", SZSERVICEDISPLAYNAME);
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}

void CmdRemoveService()
{
    SC_HANDLE       schService;
    SC_HANDLE       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if (schSCManager)
    {
        schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
        if (schService)
        {
            ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus);

            printf("Stopping %S.\n", SZSERVICEDISPLAYNAME);
            int retry = 5;

            while(QueryServiceStatus(schService, &ssStatus) && retry)
            {
                if (ssStatus.dwCurrentState == SERVICE_STOPPED)
                    break;
                if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
                    Sleep(1000);
                else
                {
                    printf("Stopping service - status %lu?\n", ssStatus.dwCurrentState);
                    Sleep(1000);
                    --retry;
                }
            }
            if (ssStatus.dwCurrentState == SERVICE_STOPPED)
            {
                printf("\n%S stopped.\n", SZSERVICEDISPLAYNAME);
            }else
            {
                printf("\n%S failed to stop.\n", SZSERVICEDISPLAYNAME);
            }

            if(DeleteService(schService))
            {
                printf("%S removed.\n", SZSERVICEDISPLAYNAME);
            } else
            {
                printf("DeleteService failed %u!\n", (UINT32)GetLastError());
            }
            CloseServiceHandle(schService);
        }
        else
        {
            printf("OpenService failed!\n");
        }
        CloseServiceHandle(schSCManager);
    }
    else
    {
        printf("OpenSCManager failed!\n");
    }
}

VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
{
    debug("Called service main %d .\n", bStop);

    if (bStop) return;

    sshStatusHandle = RegisterServiceCtrlHandler(SZSERVICENAME, service_ctrl);
    if (sshStatusHandle)
    {
        ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
        ssStatus.dwServiceSpecificExitCode = 0;

        if (ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
            ServiceStart(NULL);

        ReportStatusToSCMgr(SERVICE_STOPPED, dwErr, 0);
    }
}

int main(int argc, char* args[])
{
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        {(wchar_t*)SZSERVICENAME, (LPSERVICE_MAIN_FUNCTION)service_main},
        {NULL, NULL}
    };

    if (argc > 1)
    {
        if (((args[1][0] == '-') || (args[1][0] == '/')))
        {
            if (!strcmp("install", args[1]+1))
            {
                bStop = FALSE;
                CmdInstallService(argc > 2);
                return 0;
            }
            else if (!strcmp("remove", args[1]+1))
            {
                bStop = TRUE;
                CmdRemoveService();
                return 0;
            }
            else
            {
                goto dispatch;
            }
        }
    }
    else
    {
        SC_HANDLE       schService = NULL;
        SC_HANDLE       schSCManager = NULL;
        SERVICE_STATUS  ssStatus;
        char buff[8];

        getDataFromRegistry(KEY_DELETE, buff);
        if (buff[0] == '+')
        {
            debug ("Called main while service is stopping!\n");
            storeKey(KEY_DELETE, "");
            return 1;
        }

        StartServiceCtrlDispatcher(dispatchTable);
        schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if (schSCManager)
        {
            schService = OpenService(schSCManager, SZSERVICENAME, SERVICE_ALL_ACCESS);
            if (schService)
            {
                debug("called main function - no args\n");
                QueryServiceStatus(schService, &ssStatus);
                if (ssStatus.dwCurrentState != SERVICE_STOPPED)
                {
                    debug("called main function - status %lu\n", ssStatus.dwCurrentState);
                    return 1;
                }
                if (StartService(schService, 0, NULL))
                {
                    printf("Starting %S.\n", SZSERVICEDISPLAYNAME);
                    Sleep(1000);
                    int retry = 5;
                    while(QueryServiceStatus(schService, &ssStatus) && retry)
                    {
                        --retry;
                        if (ssStatus.dwCurrentState == SERVICE_START_PENDING)
                            Sleep(1000);
                        else
                            break;
                    }
                    if (ssStatus.dwCurrentState == SERVICE_RUNNING)
                    {
                        printf("\n%S started.\n", SZSERVICENAME);
                    }
                    else
                    {
                        printf("\n%S failed to start.\n", SZSERVICENAME);
                    }
                }
                else
                {
                    printf("\nFailed to start %S.\n", SZSERVICENAME);
                }
                CloseServiceHandle(schService);
            }
            else
            {
                printf("Failed to load the service... \n");
                return 1;
            }
        }

        CloseServiceHandle(schSCManager);
        return 0;
    }

dispatch:
    printf("Usage\n"
           "  -install\t\tinstall the service\n"
           "  -remove \t\tremove the service\n");
    return 1;
}
<|endoftext|>


<commit_before>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

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

#include <dlfcn.h>

#include <mach/mach.h>

#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

#ifdef TARGET_OS_IPHONE
#include <mach/vm_map.h>
#define mach_vm_allocate vm_allocate
#define mach_vm_protect vm_protect
#define mach_vm_write vm_write
#define mach_vm_address_t vm_address_t
#else
#include <mach/mach_vm.h>
#endif

#include <mach/machine/thread_status.h>

#include <cstdio>
#include <pthread.h>
#include <unistd.h>

#include "Baton.hpp"
#include "Exception.hpp"
#include "Pooling.hpp"
#include "Trampoline.t.hpp"

extern "C" void CYHandleServer(pid_t);

void InjectLibrary(pid_t pid) {
    Dl_info addr;
    _assert(dladdr(reinterpret_cast<void *>(&CYHandleServer), &addr) != 0);
    const char *library(addr.dli_fname);

    mach_port_t self(mach_task_self()), task;
    _krncall(task_for_pid(self, pid, &task));

    mach_msg_type_number_t count;

    task_dyld_info info;
    count = TASK_DYLD_INFO_COUNT;
    _krncall(task_info(task, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&info), &count));
    _assert(count == TASK_DYLD_INFO_COUNT);
    _assert(info.all_image_info_addr != 0);

    thread_act_t thread;
    _krncall(thread_create(task, &thread));

    thread_state_flavor_t flavor;
#if defined (__i386__) || defined(__x86_64__)
    x86_thread_state_t state;
    flavor = x86_THREAD_STATE;
    count = x86_THREAD_STATE_COUNT;
#elif defined(__arm__)
    arm_thread_state_t state;
    flavor = ARM_THREAD_STATE;
    count = ARM_THREAD_STATE_COUNT;
#else
    #error XXX: implement
#endif

    memset(&state, 0, sizeof(state));
    mach_msg_type_number_t read(count);
    _krncall(thread_get_state(thread, flavor, reinterpret_cast<thread_state_t>(&state), &read));
    _assert(read == count);

    Trampoline *trampoline;
    size_t align;
    size_t push;

#if defined(__i386__) || defined(__x86_64__)
    switch (state.tsh.flavor) {
        case i386_THREAD_STATE:
            trampoline = &Trampoline_i386_;
            align = 4;
            push = 5;
            break;
        case x86_THREAD_STATE64:
            trampoline = &Trampoline_x86_64_;
            align = 8;
            push = 2;
            break;
        default:
            _assert(false);
    }
#elif defined(__arm__)
    trampoline = &Trampoline_armv6_;
    align = 4;
    push = 0;
#else
    #error XXX: implement
#endif

    static const size_t Stack_(8 * 1024);
    size_t length(strlen(library) + 1), depth(sizeof(Baton) + length);
    depth = (depth + align + 1) / align * align;

    CYPool pool;
    uint8_t *local(pool.malloc<uint8_t>(depth));
    Baton *baton(reinterpret_cast<Baton *>(local));

    baton->dyld = info.all_image_info_addr;
    baton->pid = getpid();
    memcpy(baton->library, library, length);

    mach_vm_size_t size(depth + Stack_);
    mach_vm_address_t stack;
    _krncall(mach_vm_allocate(task, &stack, size, true));

    mach_vm_address_t data(stack + Stack_);
    _krncall(mach_vm_write(task, data, reinterpret_cast<mach_vm_address_t>(baton), depth));

    mach_vm_address_t code;
    _krncall(mach_vm_allocate(task, &code, trampoline->size_, true));
    _krncall(mach_vm_write(task, code, reinterpret_cast<mach_vm_address_t>(trampoline->data_), trampoline->size_));
    _krncall(mach_vm_protect(task, code, trampoline->size_, false, VM_PROT_READ | VM_PROT_EXECUTE));

    uint32_t frame[push];
    if (sizeof(frame) != 0)
        memset(frame, 0, sizeof(frame));

#if defined(__i386__) || defined(__x86_64__)
    switch (state.tsh.flavor) {
        case i386_THREAD_STATE:
            frame[1] = data;
            state.uts.ts32.__eip = code + trampoline->entry_;
            state.uts.ts32.__esp = stack + Stack_ - sizeof(frame);
            break;
        case x86_THREAD_STATE64:
            state.uts.ts64.__rdi = data;
            state.uts.ts64.__rip = code + trampoline->entry_;
            state.uts.ts64.__rsp = stack + Stack_ - sizeof(frame);
            break;
        default:
            _assert(false);
    }
#elif defined(__arm__)
    state.__r[0] = data;
    state.__pc = code + trampoline->entry_;
    state.__sp = stack + Stack_ - sizeof(frame);

    if ((state.__pc & 0x1) != 0) {
        state.__pc &= ~0x1;
        state.__cpsr |= 0x20;
    }
#else
    #error XXX: implement
#endif

    if (sizeof(frame) != 0)
        _krncall(mach_vm_write(task, stack + Stack_ - sizeof(frame), reinterpret_cast<mach_vm_address_t>(frame), sizeof(frame)));

    _krncall(thread_set_state(thread, flavor, reinterpret_cast<thread_state_t>(&state), count));
    _krncall(thread_resume(thread));

    _krncall(mach_port_deallocate(self, task));
}
<commit_msg>Use MACHINE_THREAD_STATE{,_COUNT} to simplify Mach.<commit_after>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

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

#include <dlfcn.h>

#include <mach/mach.h>

#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

#ifdef TARGET_OS_IPHONE
#include <mach/vm_map.h>
#define mach_vm_allocate vm_allocate
#define mach_vm_protect vm_protect
#define mach_vm_write vm_write
#define mach_vm_address_t vm_address_t
#else
#include <mach/mach_vm.h>
#endif

#include <mach/machine/thread_status.h>

#include <cstdio>
#include <pthread.h>
#include <unistd.h>

#include "Baton.hpp"
#include "Exception.hpp"
#include "Pooling.hpp"
#include "Trampoline.t.hpp"

extern "C" void CYHandleServer(pid_t);

void InjectLibrary(pid_t pid) {
    Dl_info addr;
    _assert(dladdr(reinterpret_cast<void *>(&CYHandleServer), &addr) != 0);
    const char *library(addr.dli_fname);

    mach_port_t self(mach_task_self()), task;
    _krncall(task_for_pid(self, pid, &task));

    mach_msg_type_number_t count;

    task_dyld_info info;
    count = TASK_DYLD_INFO_COUNT;
    _krncall(task_info(task, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&info), &count));
    _assert(count == TASK_DYLD_INFO_COUNT);
    _assert(info.all_image_info_addr != 0);

    thread_act_t thread;
    _krncall(thread_create(task, &thread));

#if defined (__i386__) || defined(__x86_64__)
    x86_thread_state_t state;
#elif defined(__arm__)
    arm_thread_state_t state;
#else
    #error XXX: implement
#endif

    memset(&state, 0, sizeof(state));
    mach_msg_type_number_t read(MACHINE_THREAD_STATE_COUNT);
    _krncall(thread_get_state(thread, MACHINE_THREAD_STATE, reinterpret_cast<thread_state_t>(&state), &read));
    _assert(read == MACHINE_THREAD_STATE_COUNT);

    Trampoline *trampoline;
    size_t align;
    size_t push;

#if defined(__i386__) || defined(__x86_64__)
    switch (state.tsh.flavor) {
        case i386_THREAD_STATE:
            trampoline = &Trampoline_i386_;
            align = 4;
            push = 5;
            break;
        case x86_THREAD_STATE64:
            trampoline = &Trampoline_x86_64_;
            align = 8;
            push = 2;
            break;
        default:
            _assert(false);
    }
#elif defined(__arm__)
    trampoline = &Trampoline_armv6_;
    align = 4;
    push = 0;
#else
    #error XXX: implement
#endif

    static const size_t Stack_(8 * 1024);
    size_t length(strlen(library) + 1), depth(sizeof(Baton) + length);
    depth = (depth + align + 1) / align * align;

    CYPool pool;
    uint8_t *local(pool.malloc<uint8_t>(depth));
    Baton *baton(reinterpret_cast<Baton *>(local));

    baton->dyld = info.all_image_info_addr;
    baton->pid = getpid();
    memcpy(baton->library, library, length);

    mach_vm_size_t size(depth + Stack_);
    mach_vm_address_t stack;
    _krncall(mach_vm_allocate(task, &stack, size, true));

    mach_vm_address_t data(stack + Stack_);
    _krncall(mach_vm_write(task, data, reinterpret_cast<mach_vm_address_t>(baton), depth));

    mach_vm_address_t code;
    _krncall(mach_vm_allocate(task, &code, trampoline->size_, true));
    _krncall(mach_vm_write(task, code, reinterpret_cast<mach_vm_address_t>(trampoline->data_), trampoline->size_));
    _krncall(mach_vm_protect(task, code, trampoline->size_, false, VM_PROT_READ | VM_PROT_EXECUTE));

    uint32_t frame[push];
    if (sizeof(frame) != 0)
        memset(frame, 0, sizeof(frame));

#if defined(__i386__) || defined(__x86_64__)
    switch (state.tsh.flavor) {
        case i386_THREAD_STATE:
            frame[1] = data;
            state.uts.ts32.__eip = code + trampoline->entry_;
            state.uts.ts32.__esp = stack + Stack_ - sizeof(frame);
            break;
        case x86_THREAD_STATE64:
            state.uts.ts64.__rdi = data;
            state.uts.ts64.__rip = code + trampoline->entry_;
            state.uts.ts64.__rsp = stack + Stack_ - sizeof(frame);
            break;
        default:
            _assert(false);
    }
#elif defined(__arm__)
    state.__r[0] = data;
    state.__pc = code + trampoline->entry_;
    state.__sp = stack + Stack_ - sizeof(frame);

    if ((state.__pc & 0x1) != 0) {
        state.__pc &= ~0x1;
        state.__cpsr |= 0x20;
    }
#else
    #error XXX: implement
#endif

    if (sizeof(frame) != 0)
        _krncall(mach_vm_write(task, stack + Stack_ - sizeof(frame), reinterpret_cast<mach_vm_address_t>(frame), sizeof(frame)));

    _krncall(thread_set_state(thread, MACHINE_THREAD_STATE, reinterpret_cast<thread_state_t>(&state), MACHINE_THREAD_STATE_COUNT));
    _krncall(thread_resume(thread));

    _krncall(mach_port_deallocate(self, task));
}
<|endoftext|>