<commit_before>/*
 * Copyright (c) 2013 Akihiro Kaneda.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1.Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   2.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.
 *   3.Neither the name of the Monochrome Soft 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 HOLDER 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.
 */
/*!
 @file AKOption.cpp
 @brief オプションクラス

 オプションを管理するクラスを定義する。
 */

#include "AKOption.h"
#include "AKEnemyShot.h"

using cocos2d::Node;
using cocos2d::Vector2;

/// オプションの画像ファイル名
static const char *kAKOptionImageFile = "Option_%02d";
/// シールドなし時のアニメーションフレーム数
static const int kAKOptionAnimationCountOfShieldOff = 2;
/// シールドあり時のアニメーションフレーム数
static const int kAKOptionAnimationCountOfShieldOn = 1;
/// 弾発射の間隔
static const int kAKOptionShotInterval = 12;
/// オプション間の距離
static const int kAKOptionSpace = 20;
/// オプションの当たり判定
static const int kAKOptionSize = 32;

/*!
 @brief オブジェクト生成処理

 オブジェクトの生成を行う。
 指定されたオプションの個数分を再帰的に生成する。
 @param count オプションの個数
 @param parent 画像を配置する親ノード
 @return 生成したオブジェクト。失敗時はnilを返す。
 */
AKOption::AKOption(int count, Node *parent)
{
    // アニメーションフレームの個数を設定する
    m_animationPattern = kAKOptionAnimationCountOfShieldOff;

    // 画像名を設定する
    char imageName[16] = "";
    snprintf(imageName, sizeof(imageName), kAKOptionImageFile, 1);
    setImageName(imageName);

    // 弾発射までの残りフレーム数を設定する
    m_shootFrame = kAKOptionShotInterval;

    // ヒットポイントは1としておく
    m_hitPoint = 1;

    // オプションの当たり判定を設定する
    // これはシールド時のみ使用する
    m_size.width = kAKOptionSize;
    m_size.height = kAKOptionSize;

    // 初期状態はシールドなしとする
    m_shield = false;

    // 初期状態では画面には配置しない
    m_isStaged = false;
    getImage()->setVisible(false);

    // 画像を親ノードに配置する
    parent->addChild(getImage());

    // オプション個数が指定されている場合は次のオプションを生成する
    if (count > 0) {
        m_next = new AKOption(count - 1, parent);
    }
    else {
        m_next = NULL;
    }
}

/*!
 @brief デストラクタ

 次のオプションを解放する。
 */
AKOption::~AKOption()
{
    delete m_next;
}

/*!
 @brief シールド有無設定

 シールド有無を設定する。
 画像の切り替えも行う。
 次のオプションに対しても同様の設定を行う。
 @param shield シールド有無
 */
void AKOption::setShiled(bool shield)
{
    // メンバに設定する
    m_shield = shield;

    // シールド有無によって画像を切り替える
    if (m_shield) {

        AKLog(kAKLogOption_1, "シールドあり");

        // 画像名を設定する
        char imageName[16] = "";
        snprintf(imageName, sizeof(imageName), kAKOptionImageFile, 2);
        setImageName(imageName);

        // アニメーションフレームの個数を設定する
        m_animationPattern = kAKOptionAnimationCountOfShieldOn;
    }
    else {

        AKLog(kAKLogOption_1, "シールドなし");

        // 画像名を設定する
        char imageName[16] = "";
        snprintf(imageName, sizeof(imageName), kAKOptionImageFile, 1);
        setImageName(imageName);

        // アニメーションフレームの個数を設定する
        m_animationPattern = kAKOptionAnimationCountOfShieldOn;
    }

    // 次のオプションがある場合は次のオプションにも設定する
    if (m_next != NULL) {
        m_next->setShiled(m_shield);
    }
}

/*!
 @brief オプション数設定

 オプションの個数を設定する。
 1以上が設定された場合は自分を配置状態に設定する。
 0以下が設定された場合は自分を配置状態から外す。
 次のオプションが存在する場合は個数を一つ減らして再帰的に呼び出す。
 @param count オプション個数
 @param position 初期配置位置
 */
void AKOption::setOptionCount(int count, const Vector2 &position)
{
    AKLog(kAKLogOption_2, "count=%d", count);

    // オプション個数が設定された場合はオプションを有効とする
    if (count > 0) {

        // 配置されていない場合は配置状態にして、初期配置位置に移動する
        if (!m_isStaged) {
            AKLog(kAKLogOption_1, "オプション配置");

            m_isStaged = true;
            getImage()->setVisible(true);
            m_position = position;

            // 初期表示時に前回の位置に表示されることを防ぐため、画像表示位置の更新も行う
            updateImagePosition();
        }
    }
    // オプション個数が0以下の場合はオプションを無効とする
    else {

        // 配置されている場合は配置状態を解除して、移動座標をすべてクリアする
        if (m_isStaged) {
            AKLog(kAKLogOption_1, "オプション削除");

            m_isStaged = false;
            getImage()->setVisible(false);
            m_movePositions.clear();
        }
    }

    // 自分の座標を初期座標として次のオプションを設定する
    if (m_next != NULL) {
        m_next->setOptionCount(count - 1, m_position);
    }
}

/*!
 @brief 移動座標設定

 移動座標を設定する。オプションが付属している場合はオプションの移動も行う。
 @param position 移動先座標
 */
void AKOption::setPosition(const Vector2 &position)
{
    // オプションに自分の移動前の座標を通知する
    if (m_next != NULL && m_next->isStaged()) {

        m_next->setPosition(m_position);
    }

    // 移動先座標が間隔分溜まっている場合は先頭の座標に移動する
    if (m_movePositions.size() >= kAKOptionSpace) {

        // 先頭の要素を取得し、座標を移動する
        std::vector<Vector2>::iterator start = m_movePositions.begin();
        m_position = *start;

        // 取得した要素を配列から取り除く
        m_movePositions.erase(start);
    }

    // 移動先座標の配列の末尾に追加する
    m_movePositions.push_back(position);
}

/*!
 @brief オプション移動

 オプションの移動を行う。自機クラスから呼び出される。
 @param data ゲームデータ
 */
void AKOption::optionMove(AKPlayDataInterface *data)
{
    move(data);
}

/*!
 @brief 次のオプション取得

 次のオプションを取得する。
 最後のオプションの場合はNULLを返す。
 @return 次のオプション
 */
AKOption* AKOption::getNext()
{
    return m_next;
}

/*!
 @brief キャラクター固有の動作

 速度によって位置を移動する。オプションの表示位置は固定とする。
 次のオプションの移動を行う。
 @param data ゲームデータ
 */
void AKOption::action(AKPlayDataInterface *data)
{
    // 弾発射までのフレーム数をカウントする
    m_shootFrame--;

    // 弾発射までの残りフレーム数が0になっている場合は弾を発射する
    if (m_shootFrame <= 0) {

        // オプション弾を生成する
        data->createOptionShot(m_position);

        // 弾発射までの残り時間をリセットする
        m_shootFrame = kAKOptionShotInterval;
    }

    // 次のオプションの移動を行う
    if (m_next != NULL) {
        m_next->move(data);
    }
}

/*!
 @brief 衝突処理

 衝突した時の処理。
 反射弾を作成後、相手のHPを0にする。
 @param character 衝突した相手
 @param data ゲームデータ
 */
void AKOption::hit(AKCharacter *character, AKPlayDataInterface *data)
{
    AKLog(kAKLogOption_1, "反射処理開始");

    // 反射弾を作成する
    data->createReflectShot(static_cast<AKEnemyShot*>(character));

    // 相手のHPを0にする
    character->setHitPoint(0);
}

<commit_msg>ひよこのアニメーション処理がシールド使用後に止まってしまうものを修正。<commit_after>/*
 * Copyright (c) 2013 Akihiro Kaneda.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1.Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   2.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.
 *   3.Neither the name of the Monochrome Soft 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 HOLDER 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.
 */
/*!
 @file AKOption.cpp
 @brief オプションクラス

 オプションを管理するクラスを定義する。
 */

#include "AKOption.h"
#include "AKEnemyShot.h"

using cocos2d::Node;
using cocos2d::Vector2;

/// オプションの画像ファイル名
static const char *kAKOptionImageFile = "Option_%02d";
/// シールドなし時のアニメーションフレーム数
static const int kAKOptionAnimationCountOfShieldOff = 2;
/// シールドあり時のアニメーションフレーム数
static const int kAKOptionAnimationCountOfShieldOn = 1;
/// 弾発射の間隔
static const int kAKOptionShotInterval = 12;
/// オプション間の距離
static const int kAKOptionSpace = 20;
/// オプションの当たり判定
static const int kAKOptionSize = 32;

/*!
 @brief オブジェクト生成処理

 オブジェクトの生成を行う。
 指定されたオプションの個数分を再帰的に生成する。
 @param count オプションの個数
 @param parent 画像を配置する親ノード
 @return 生成したオブジェクト。失敗時はnilを返す。
 */
AKOption::AKOption(int count, Node *parent)
{
    // アニメーションフレームの個数を設定する
    m_animationPattern = kAKOptionAnimationCountOfShieldOff;

    // 画像名を設定する
    char imageName[16] = "";
    snprintf(imageName, sizeof(imageName), kAKOptionImageFile, 1);
    setImageName(imageName);

    // 弾発射までの残りフレーム数を設定する
    m_shootFrame = kAKOptionShotInterval;

    // ヒットポイントは1としておく
    m_hitPoint = 1;

    // オプションの当たり判定を設定する
    // これはシールド時のみ使用する
    m_size.width = kAKOptionSize;
    m_size.height = kAKOptionSize;

    // 初期状態はシールドなしとする
    m_shield = false;

    // 初期状態では画面には配置しない
    m_isStaged = false;
    getImage()->setVisible(false);

    // 画像を親ノードに配置する
    parent->addChild(getImage());

    // オプション個数が指定されている場合は次のオプションを生成する
    if (count > 0) {
        m_next = new AKOption(count - 1, parent);
    }
    else {
        m_next = NULL;
    }
}

/*!
 @brief デストラクタ

 次のオプションを解放する。
 */
AKOption::~AKOption()
{
    delete m_next;
}

/*!
 @brief シールド有無設定

 シールド有無を設定する。
 画像の切り替えも行う。
 次のオプションに対しても同様の設定を行う。
 @param shield シールド有無
 */
void AKOption::setShiled(bool shield)
{
    // メンバに設定する
    m_shield = shield;

    // シールド有無によって画像を切り替える
    if (m_shield) {

        AKLog(kAKLogOption_1, "シールドあり");

        // 画像名を設定する
        char imageName[16] = "";
        snprintf(imageName, sizeof(imageName), kAKOptionImageFile, 2);
        setImageName(imageName);

        // アニメーションフレームの個数を設定する
        m_animationPattern = kAKOptionAnimationCountOfShieldOn;
    }
    else {

        AKLog(kAKLogOption_1, "シールドなし");

        // 画像名を設定する
        char imageName[16] = "";
        snprintf(imageName, sizeof(imageName), kAKOptionImageFile, 1);
        setImageName(imageName);

        // アニメーションフレームの個数を設定する
        m_animationPattern = kAKOptionAnimationCountOfShieldOff;
    }

    // 次のオプションがある場合は次のオプションにも設定する
    if (m_next != NULL) {
        m_next->setShiled(m_shield);
    }
}

/*!
 @brief オプション数設定

 オプションの個数を設定する。
 1以上が設定された場合は自分を配置状態に設定する。
 0以下が設定された場合は自分を配置状態から外す。
 次のオプションが存在する場合は個数を一つ減らして再帰的に呼び出す。
 @param count オプション個数
 @param position 初期配置位置
 */
void AKOption::setOptionCount(int count, const Vector2 &position)
{
    AKLog(kAKLogOption_2, "count=%d", count);

    // オプション個数が設定された場合はオプションを有効とする
    if (count > 0) {

        // 配置されていない場合は配置状態にして、初期配置位置に移動する
        if (!m_isStaged) {
            AKLog(kAKLogOption_1, "オプション配置");

            m_isStaged = true;
            getImage()->setVisible(true);
            m_position = position;

            // 初期表示時に前回の位置に表示されることを防ぐため、画像表示位置の更新も行う
            updateImagePosition();
        }
    }
    // オプション個数が0以下の場合はオプションを無効とする
    else {

        // 配置されている場合は配置状態を解除して、移動座標をすべてクリアする
        if (m_isStaged) {
            AKLog(kAKLogOption_1, "オプション削除");

            m_isStaged = false;
            getImage()->setVisible(false);
            m_movePositions.clear();
        }
    }

    // 自分の座標を初期座標として次のオプションを設定する
    if (m_next != NULL) {
        m_next->setOptionCount(count - 1, m_position);
    }
}

/*!
 @brief 移動座標設定

 移動座標を設定する。オプションが付属している場合はオプションの移動も行う。
 @param position 移動先座標
 */
void AKOption::setPosition(const Vector2 &position)
{
    // オプションに自分の移動前の座標を通知する
    if (m_next != NULL && m_next->isStaged()) {

        m_next->setPosition(m_position);
    }

    // 移動先座標が間隔分溜まっている場合は先頭の座標に移動する
    if (m_movePositions.size() >= kAKOptionSpace) {

        // 先頭の要素を取得し、座標を移動する
        std::vector<Vector2>::iterator start = m_movePositions.begin();
        m_position = *start;

        // 取得した要素を配列から取り除く
        m_movePositions.erase(start);
    }

    // 移動先座標の配列の末尾に追加する
    m_movePositions.push_back(position);
}

/*!
 @brief オプション移動

 オプションの移動を行う。自機クラスから呼び出される。
 @param data ゲームデータ
 */
void AKOption::optionMove(AKPlayDataInterface *data)
{
    move(data);
}

/*!
 @brief 次のオプション取得

 次のオプションを取得する。
 最後のオプションの場合はNULLを返す。
 @return 次のオプション
 */
AKOption* AKOption::getNext()
{
    return m_next;
}

/*!
 @brief キャラクター固有の動作

 速度によって位置を移動する。オプションの表示位置は固定とする。
 次のオプションの移動を行う。
 @param data ゲームデータ
 */
void AKOption::action(AKPlayDataInterface *data)
{
    // 弾発射までのフレーム数をカウントする
    m_shootFrame--;

    // 弾発射までの残りフレーム数が0になっている場合は弾を発射する
    if (m_shootFrame <= 0) {

        // オプション弾を生成する
        data->createOptionShot(m_position);

        // 弾発射までの残り時間をリセットする
        m_shootFrame = kAKOptionShotInterval;
    }

    // 次のオプションの移動を行う
    if (m_next != NULL) {
        m_next->move(data);
    }
}

/*!
 @brief 衝突処理

 衝突した時の処理。
 反射弾を作成後、相手のHPを0にする。
 @param character 衝突した相手
 @param data ゲームデータ
 */
void AKOption::hit(AKCharacter *character, AKPlayDataInterface *data)
{
    AKLog(kAKLogOption_1, "反射処理開始");

    // 反射弾を作成する
    data->createReflectShot(static_cast<AKEnemyShot*>(character));

    // 相手のHPを0にする
    character->setHitPoint(0);
}

<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

extern "C" {
#include "php.h"
}
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_mmseg.h"
#include <sys/stat.h>

using namespace std;

// SegmenterManager
ZEND_DECLARE_MODULE_GLOBALS(mmseg)

	/* True global resources - no need for thread safety here */
	static int le_mmseg;
	// mmseg segmenter manager句柄
	static int le_mmseg_descriptor;

	/* {{{ PHP_INI
	 */
PHP_INI_BEGIN()
	PHP_INI_ENTRY("mmseg.dict_dir", "/opt/etc", PHP_INI_ALL, NULL)
	PHP_INI_ENTRY("mmseg.autoreload", "1", PHP_INI_ALL, NULL)
PHP_INI_END()
	/* }}} */

	/* {{{ php_mmseg_init_globals
	 */
	/* Uncomment this function if you have INI entries
	   static void php_mmseg_init_globals(zend_mmseg_globals *mmseg_globals)
	   {
	   mmseg_globals->global_value = 0;
	   mmseg_globals->global_string = NULL;
	   }
	 */
	/* }}} */

	/* {{{ PHP_MINIT_FUNCTION
	 */
PHP_MINIT_FUNCTION(mmseg)
{
	REGISTER_INI_ENTRIES();
	// 初始化mmseg资源句柄
	le_mmseg_descriptor = zend_register_list_destructors_ex(php_mmseg_descriptor_dtor, NULL, PHP_MMSEG_DESCRIPTOR_RES_NAME,module_number);
	// 初始化，如果初始化失败，则返回失败信息，(XXX: 未来将改变为如果初始化失败, 可以在程序里面调用init初始化)
#ifdef ZTS
	ts_allocate_id(&mmseg_globals_id, sizeof(zend_mmseg_globals),
			php_mmseg_globals_ctor, php_mmseg_globals_dtor);
#else
	php_mmseg_globals_ctor(&mmseg_globals TSRMLS_CC);
#endif
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(mmseg)
{
	UNREGISTER_INI_ENTRIES();
#ifndef ZTS
	php_mmseg_globals_dtor(&mmseg_globals TSRMLS_CC);
#endif
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(mmseg)
{
#if defined(COMPILE_DL_MMSEG) && defined(ZTS) && defined(ZEND_TSRMLS_CACHE_UPDATE)
	ZEND_TSRMLS_CACHE_UPDATE();
#endif
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(mmseg)
{
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(mmseg)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "mmseg support", "enabled");
	php_info_print_table_end();

	DISPLAY_INI_ENTRIES();
}
/* }}} */

/* {{{ mmseg_functions[]
 *
 * Every user visible function must have an entry in mmseg_functions[].
 */
const zend_function_entry mmseg_functions[] = {
	PHP_FE(mmseg_segment,	NULL)
		PHP_FE(mmseg_open,	    NULL)
		PHP_FE(mmseg_close,	    NULL)
		PHP_FE(mmseg_gendict,	NULL)
		PHP_FE(mmseg_gensynonyms,	NULL)
		PHP_FE(mmseg_genthesaurus,	NULL)
		PHP_FE_END	/* Must be the last line in mmseg_functions[] */
};
/* }}} */

/* {{{ mmseg_module_entry
 */
zend_module_entry mmseg_module_entry = {
	STANDARD_MODULE_HEADER,
	"mmseg",
	mmseg_functions,
	PHP_MINIT(mmseg),
	PHP_MSHUTDOWN(mmseg),
	PHP_RINIT(mmseg),		/* Replace with NULL if there's nothing to do at request start */
	PHP_RSHUTDOWN(mmseg),	/* Replace with NULL if there's nothing to do at request end */
	PHP_MINFO(mmseg),
	PHP_MMSEG_VERSION,
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_MMSEG
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
	BEGIN_EXTERN_C()
	ZEND_GET_MODULE(mmseg)
END_EXTERN_C()
#endif

	/* Triggered at the beginning of a thread */
static void php_mmseg_globals_ctor(zend_mmseg_globals *mmseg_globals TSRMLS_DC)
{
	struct stat st;
	SegmenterManager* mgr = (SegmenterManager*) mmseg_globals->mgr;
	mgr = new SegmenterManager();
	int nRet = 0;
	mmseg_globals->dict_mtime = 0;
	nRet = mgr->init(INI_STR("mmseg.dict_dir"));
	if (nRet == 0) {
		mmseg_globals->mgr = (void*) mgr;
		// 记录最后一次字典文件更改的数值
		string dict_file_path;
		dict_file_path = INI_STR("mmseg.dict_dir");
		dict_file_path.append("/uni.lib");

		if (stat(dict_file_path.c_str(), &st) == 0) {
			mmseg_globals->dict_mtime = st.st_mtime;
			MMSEG_LOG(ctime(&st.st_mtime));
		}

		MMSEG_LOG("minit load dictionary");
		return ;
	} else {
		if (mgr != NULL)  {
			delete mgr;
			mgr = NULL;
		}
		mmseg_globals->mgr = NULL;
		return ;
	}
}

/* Triggered at the end of a thread */
static void php_mmseg_globals_dtor(zend_mmseg_globals *mmseg_globals TSRMLS_DC)
{
	SegmenterManager* mgr = (SegmenterManager*) mmseg_globals->mgr;
	if (mgr != NULL)  {
		delete mgr;
		mgr = NULL;
	}
}

// mmseg 句柄的dtor函数
static void php_mmseg_descriptor_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	SegmenterManager *mgr = (SegmenterManager*)rsrc->ptr;
	if (mgr != NULL) {
		delete mgr;
		mgr = NULL;
	}
}

/* The previous line is meant for vim and emacs, so it can correctly fold and
   unfold functions in source code. See the corresponding marks just before
   function definition, where the functions purpose is also documented. Please
   follow this convention for the convenience of others editing your code.
 */

/* {{{ proto array mmseg_segment(string content)
 */
PHP_FUNCTION(mmseg_segment)
{
	char *content = NULL;
	int argc = ZEND_NUM_ARGS();
#if PHP_MAJOR_VERSION < 7
	int content_len;
#else
	size_t content_len;
#endif
	SegmenterManager* mgr =  NULL;
	zval *mmseg_resource;

	zend_bool autoreload = INI_BOOL("mmseg.autoreload");

	// 判断传入参数的数量
	if (argc == 1) {
		struct stat st;
		if (zend_parse_parameters(argc TSRMLS_CC, "s", &content, &content_len) == FAILURE)
			return;
		// 如果使用全局的字典文件，在这里看一下是否需要判断文件是否有改变
		if (1 == autoreload) {
			// 文件名
			string dict_file_path;
			dict_file_path = INI_STR("mmseg.dict_dir");
			dict_file_path.append("/uni.lib");

			if (stat(dict_file_path.c_str(), &st) == 0) {
				if (st.st_mtime != MMSEG_G(dict_mtime)) {
					MMSEG_G(dict_mtime) = st.st_mtime;
					SegmenterManager* oldMgr = (SegmenterManager*)MMSEG_G(mgr);
					SegmenterManager* newMgr;
					newMgr = new SegmenterManager();
					int nRet = 0;
					nRet = newMgr->init(INI_STR("mmseg.dict_dir"));
					if (nRet == 0) {
						if (oldMgr) {
							MMSEG_LOG("trying to delete old mgr");
							delete oldMgr;
							oldMgr = NULL;
						}

						MMSEG_LOG("load dictionary on change");
						MMSEG_G(mgr) = newMgr;
					} else {
						// no change. still use oldMgr
						MMSEG_LOG("no change, initialize new dict file failed");
						newMgr = NULL;
					}
				} else {
					MMSEG_LOG(ctime(&st.st_mtime));
					MMSEG_LOG(ctime(&MMSEG_G(dict_mtime)));
					MMSEG_LOG("no change, dict file no change");
					// no change, still  use old oldMgr
				}
			} else {
				MMSEG_LOG("no change, stat new dict file failed");
			}
		} else {
			MMSEG_LOG("no change, autoreload not set");
		}
	} else if (argc == 2){
		if (zend_parse_parameters(argc TSRMLS_CC, "rs", &mmseg_resource, &content, &content_len) == FAILURE)
			return;
#if PHP_MAJOR_VERSION < 7
		ZEND_FETCH_RESOURCE(mgr,SegmenterManager*,&mmseg_resource,-1,PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
#else
		mgr = (SegmenterManager*) zend_fetch_resource(Z_RES_P(mmseg_resource), PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
#endif

	} else {
		return;
	}

	mgr = (SegmenterManager*) MMSEG_G(mgr);
	if (mgr == NULL) {
		RETURN_NULL();
	}

	Segmenter* seg = mgr->getSegmenter();
	u4 content_length = content_len;
	seg->setBuffer((u1*)content, content_length);
	array_init(return_value);
	while(1)
	{
		u2 len = 0, symlen = 0;
		char* tok = (char*)seg->peekToken(len,symlen);
		if(!tok || !*tok || !len){
			break;
		}
		//append new item
#if PHP_MAJOR_VERSION < 7
		add_next_index_stringl(return_value, tok, len, 1);
#else
		add_next_index_stringl(return_value, tok, len);
#endif
		seg->popToken(len);
	}
	return ;
}
/* }}} */

PHP_FUNCTION(mmseg_open)
{
	char *path = NULL;
	int argc = ZEND_NUM_ARGS();
#if PHP_MAJOR_VERSION < 7
	int path_len;
#else
	size_t path_len;
#endif

	if (zend_parse_parameters(argc TSRMLS_CC, "s", &path, &path_len) == FAILURE)
		return;
	// 生成新的对象
	SegmenterManager* mgr = new SegmenterManager();
	int nRet = 0;
	nRet = mgr->init(path);
	if (nRet == 0) {
		// 注册这个资源
#if PHP_MAJOR_VERSION < 7
		ZEND_REGISTER_RESOURCE(return_value,mgr,le_mmseg_descriptor);
#else
		RETURN_RES(zend_register_resource(mgr, le_mmseg_descriptor));
#endif
	} else {
		RETURN_NULL();
	}
}

PHP_FUNCTION(mmseg_close)
{
	zval *mmseg_resource;
	SegmenterManager* mgr;
	int argc = ZEND_NUM_ARGS();

	if (zend_parse_parameters(argc TSRMLS_CC, "r", &mmseg_resource) == FAILURE)
		return;
#if PHP_MAJOR_VERSION < 7
	ZEND_FETCH_RESOURCE(mgr,SegmenterManager*,&mmseg_resource,-1,PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
	zend_hash_index_del(&EG(regular_list),Z_RESVAL_P(mmseg_resource));
#else
	mgr = (SegmenterManager*) zend_fetch_resource(Z_RES_P(mmseg_resource), PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
	zend_hash_index_del(&EG(regular_list),Z_RES_P(mmseg_resource)->handle);
#endif

	RETURN_TRUE;
}

// 字典的生成
PHP_FUNCTION(mmseg_gendict)
{
	int argc = ZEND_NUM_ARGS();

	char *path = NULL;

	char *target = NULL;

#if PHP_MAJOR_VERSION < 7
	int target_len;
	int path_len;
#else
	size_t target_len;
	size_t path_len;
#endif

	zend_bool b_plainText = 0;

	if (zend_parse_parameters(argc TSRMLS_CC, "ss", &path, &path_len, &target, &target_len) == FAILURE)
		return;

	UnigramCorpusReader ur;
	ur.open(path,b_plainText?"plain":NULL);
	UnigramDict ud;
	int ret = ud.import(ur);
	ud.save(target);
	//check
	int i = 0;
	for(i=0;i<ur.count();i++)
	{
		UnigramRecord* rec = ur.getAt(i);

		if(ud.exactMatch(rec->key.c_str()) == rec->count){
			continue;
		}else{
			RETURN_FALSE;
		}
	}//end for

	RETURN_TRUE;
}

// 特殊短语字典的生成
PHP_FUNCTION(mmseg_gensynonyms)
{
	int argc = ZEND_NUM_ARGS();

	char *path = NULL;

	char *target = NULL;

#if PHP_MAJOR_VERSION < 7
	int path_len;
	int target_len;
#else
	size_t path_len;
	size_t target_len;
#endif

	zend_bool b_plainText = 0;

	if (zend_parse_parameters(argc TSRMLS_CC, "ss", &path, &path_len, &target, &target_len) == FAILURE)
		return;

	SynonymsDict dict;
	dict.import(path);
	if(target)
		dict.save(target);
	else
		dict.save("synonyms.dat");

	RETURN_TRUE;
}

// 同义词词典的生成
PHP_FUNCTION(mmseg_genthesaurus)
{
	int argc = ZEND_NUM_ARGS();

	char *path = NULL;

	char *target = NULL;

#if PHP_MAJOR_VERSION < 7
	int path_len;
	int target_len;
#else
	size_t path_len;
	size_t target_len;
#endif

	zend_bool b_plainText = 0;

	if (zend_parse_parameters(argc TSRMLS_CC, "ss", &path, &path_len, &target, &target_len) == FAILURE)
		return;

	ThesaurusDict tdict;
	tdict.import(path, target);
	RETURN_TRUE;
}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
<commit_msg>change static pos<commit_after>#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

extern "C" {
#include "php.h"
}
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_mmseg.h"
#include <sys/stat.h>

using namespace std;

// SegmenterManager
ZEND_DECLARE_MODULE_GLOBALS(mmseg)

	/* True global resources - no need for thread safety here */
	static int le_mmseg;
	// mmseg segmenter manager句柄
	static int le_mmseg_descriptor;

	/* {{{ PHP_INI
	 */
PHP_INI_BEGIN()
	PHP_INI_ENTRY("mmseg.dict_dir", "/opt/etc", PHP_INI_ALL, NULL)
	PHP_INI_ENTRY("mmseg.autoreload", "1", PHP_INI_ALL, NULL)
PHP_INI_END()
	/* }}} */

	/* Triggered at the beginning of a thread */
static void php_mmseg_globals_ctor(zend_mmseg_globals *mmseg_globals TSRMLS_DC)
{
	struct stat st;
	SegmenterManager* mgr = (SegmenterManager*) mmseg_globals->mgr;
	mgr = new SegmenterManager();
	int nRet = 0;
	mmseg_globals->dict_mtime = 0;
	nRet = mgr->init(INI_STR("mmseg.dict_dir"));
	if (nRet == 0) {
		mmseg_globals->mgr = (void*) mgr;
		// 记录最后一次字典文件更改的数值
		string dict_file_path;
		dict_file_path = INI_STR("mmseg.dict_dir");
		dict_file_path.append("/uni.lib");

		if (stat(dict_file_path.c_str(), &st) == 0) {
			mmseg_globals->dict_mtime = st.st_mtime;
			MMSEG_LOG(ctime(&st.st_mtime));
		}

		MMSEG_LOG("minit load dictionary");
		return ;
	} else {
		if (mgr != NULL)  {
			delete mgr;
			mgr = NULL;
		}
		mmseg_globals->mgr = NULL;
		return ;
	}
}

/* Triggered at the end of a thread */
static void php_mmseg_globals_dtor(zend_mmseg_globals *mmseg_globals TSRMLS_DC)
{
	SegmenterManager* mgr = (SegmenterManager*) mmseg_globals->mgr;
	if (mgr != NULL)  {
		delete mgr;
		mgr = NULL;
	}
}

// mmseg 句柄的dtor函数
static void php_mmseg_descriptor_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	SegmenterManager *mgr = (SegmenterManager*)rsrc->ptr;
	if (mgr != NULL) {
		delete mgr;
		mgr = NULL;
	}
}

	/* {{{ PHP_MINIT_FUNCTION
	 */
PHP_MINIT_FUNCTION(mmseg)
{
	REGISTER_INI_ENTRIES();
	// 初始化mmseg资源句柄
	le_mmseg_descriptor = zend_register_list_destructors_ex(php_mmseg_descriptor_dtor, NULL, PHP_MMSEG_DESCRIPTOR_RES_NAME,module_number);
	// 初始化，如果初始化失败，则返回失败信息，(XXX: 未来将改变为如果初始化失败, 可以在程序里面调用init初始化)
#ifdef ZTS
	ts_allocate_id(&mmseg_globals_id, sizeof(zend_mmseg_globals),
			php_mmseg_globals_ctor, php_mmseg_globals_dtor);
#else
	php_mmseg_globals_ctor(&mmseg_globals TSRMLS_CC);
#endif
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(mmseg)
{
	UNREGISTER_INI_ENTRIES();
#ifndef ZTS
	php_mmseg_globals_dtor(&mmseg_globals TSRMLS_CC);
#endif
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(mmseg)
{
#if defined(COMPILE_DL_MMSEG) && defined(ZTS) && defined(ZEND_TSRMLS_CACHE_UPDATE)
	ZEND_TSRMLS_CACHE_UPDATE();
#endif
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(mmseg)
{
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(mmseg)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "mmseg support", "enabled");
	php_info_print_table_end();

	DISPLAY_INI_ENTRIES();
}
/* }}} */

/* {{{ mmseg_functions[]
 *
 * Every user visible function must have an entry in mmseg_functions[].
 */
const zend_function_entry mmseg_functions[] = {
	PHP_FE(mmseg_segment,	NULL)
		PHP_FE(mmseg_open,	    NULL)
		PHP_FE(mmseg_close,	    NULL)
		PHP_FE(mmseg_gendict,	NULL)
		PHP_FE(mmseg_gensynonyms,	NULL)
		PHP_FE(mmseg_genthesaurus,	NULL)
		PHP_FE_END	/* Must be the last line in mmseg_functions[] */
};
/* }}} */

/* {{{ mmseg_module_entry
 */
zend_module_entry mmseg_module_entry = {
	STANDARD_MODULE_HEADER,
	"mmseg",
	mmseg_functions,
	PHP_MINIT(mmseg),
	PHP_MSHUTDOWN(mmseg),
	PHP_RINIT(mmseg),		/* Replace with NULL if there's nothing to do at request start */
	PHP_RSHUTDOWN(mmseg),	/* Replace with NULL if there's nothing to do at request end */
	PHP_MINFO(mmseg),
	PHP_MMSEG_VERSION,
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_MMSEG
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
	BEGIN_EXTERN_C()
	ZEND_GET_MODULE(mmseg)
END_EXTERN_C()
#endif

/* The previous line is meant for vim and emacs, so it can correctly fold and
   unfold functions in source code. See the corresponding marks just before
   function definition, where the functions purpose is also documented. Please
   follow this convention for the convenience of others editing your code.
 */

/* {{{ proto array mmseg_segment(string content)
 */
PHP_FUNCTION(mmseg_segment)
{
	char *content = NULL;
	int argc = ZEND_NUM_ARGS();
#if PHP_MAJOR_VERSION < 7
	int content_len;
#else
	size_t content_len;
#endif
	SegmenterManager* mgr =  NULL;
	zval *mmseg_resource;

	zend_bool autoreload = INI_BOOL("mmseg.autoreload");

	// 判断传入参数的数量
	if (argc == 1) {
		struct stat st;
		if (zend_parse_parameters(argc TSRMLS_CC, "s", &content, &content_len) == FAILURE)
			return;
		// 如果使用全局的字典文件，在这里看一下是否需要判断文件是否有改变
		if (1 == autoreload) {
			// 文件名
			string dict_file_path;
			dict_file_path = INI_STR("mmseg.dict_dir");
			dict_file_path.append("/uni.lib");

			if (stat(dict_file_path.c_str(), &st) == 0) {
				if (st.st_mtime != MMSEG_G(dict_mtime)) {
					MMSEG_G(dict_mtime) = st.st_mtime;
					SegmenterManager* oldMgr = (SegmenterManager*)MMSEG_G(mgr);
					SegmenterManager* newMgr;
					newMgr = new SegmenterManager();
					int nRet = 0;
					nRet = newMgr->init(INI_STR("mmseg.dict_dir"));
					if (nRet == 0) {
						if (oldMgr) {
							MMSEG_LOG("trying to delete old mgr");
							delete oldMgr;
							oldMgr = NULL;
						}

						MMSEG_LOG("load dictionary on change");
						MMSEG_G(mgr) = newMgr;
					} else {
						// no change. still use oldMgr
						MMSEG_LOG("no change, initialize new dict file failed");
						newMgr = NULL;
					}
				} else {
					MMSEG_LOG(ctime(&st.st_mtime));
					MMSEG_LOG(ctime(&MMSEG_G(dict_mtime)));
					MMSEG_LOG("no change, dict file no change");
					// no change, still  use old oldMgr
				}
			} else {
				MMSEG_LOG("no change, stat new dict file failed");
			}
		} else {
			MMSEG_LOG("no change, autoreload not set");
		}
	} else if (argc == 2){
		if (zend_parse_parameters(argc TSRMLS_CC, "rs", &mmseg_resource, &content, &content_len) == FAILURE)
			return;
#if PHP_MAJOR_VERSION < 7
		ZEND_FETCH_RESOURCE(mgr,SegmenterManager*,&mmseg_resource,-1,PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
#else
		mgr = (SegmenterManager*) zend_fetch_resource(Z_RES_P(mmseg_resource), PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
#endif

	} else {
		return;
	}

	mgr = (SegmenterManager*) MMSEG_G(mgr);
	if (mgr == NULL) {
		RETURN_NULL();
	}

	Segmenter* seg = mgr->getSegmenter();
	u4 content_length = content_len;
	seg->setBuffer((u1*)content, content_length);
	array_init(return_value);
	while(1)
	{
		u2 len = 0, symlen = 0;
		char* tok = (char*)seg->peekToken(len,symlen);
		if(!tok || !*tok || !len){
			break;
		}
		//append new item
#if PHP_MAJOR_VERSION < 7
		add_next_index_stringl(return_value, tok, len, 1);
#else
		add_next_index_stringl(return_value, tok, len);
#endif
		seg->popToken(len);
	}
	return ;
}
/* }}} */

PHP_FUNCTION(mmseg_open)
{
	char *path = NULL;
	int argc = ZEND_NUM_ARGS();
#if PHP_MAJOR_VERSION < 7
	int path_len;
#else
	size_t path_len;
#endif

	if (zend_parse_parameters(argc TSRMLS_CC, "s", &path, &path_len) == FAILURE)
		return;
	// 生成新的对象
	SegmenterManager* mgr = new SegmenterManager();
	int nRet = 0;
	nRet = mgr->init(path);
	if (nRet == 0) {
		// 注册这个资源
#if PHP_MAJOR_VERSION < 7
		ZEND_REGISTER_RESOURCE(return_value,mgr,le_mmseg_descriptor);
#else
		RETURN_RES(zend_register_resource(mgr, le_mmseg_descriptor));
#endif
	} else {
		RETURN_NULL();
	}
}

PHP_FUNCTION(mmseg_close)
{
	zval *mmseg_resource;
	SegmenterManager* mgr;
	int argc = ZEND_NUM_ARGS();

	if (zend_parse_parameters(argc TSRMLS_CC, "r", &mmseg_resource) == FAILURE)
		return;
#if PHP_MAJOR_VERSION < 7
	ZEND_FETCH_RESOURCE(mgr,SegmenterManager*,&mmseg_resource,-1,PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
	zend_hash_index_del(&EG(regular_list),Z_RESVAL_P(mmseg_resource));
#else
	mgr = (SegmenterManager*) zend_fetch_resource(Z_RES_P(mmseg_resource), PHP_MMSEG_DESCRIPTOR_RES_NAME,le_mmseg_descriptor);
	zend_hash_index_del(&EG(regular_list),Z_RES_P(mmseg_resource)->handle);
#endif

	RETURN_TRUE;
}

// 字典的生成
PHP_FUNCTION(mmseg_gendict)
{
	int argc = ZEND_NUM_ARGS();

	char *path = NULL;

	char *target = NULL;

#if PHP_MAJOR_VERSION < 7
	int target_len;
	int path_len;
#else
	size_t target_len;
	size_t path_len;
#endif

	zend_bool b_plainText = 0;

	if (zend_parse_parameters(argc TSRMLS_CC, "ss", &path, &path_len, &target, &target_len) == FAILURE)
		return;

	UnigramCorpusReader ur;
	ur.open(path,b_plainText?"plain":NULL);
	UnigramDict ud;
	int ret = ud.import(ur);
	ud.save(target);
	//check
	int i = 0;
	for(i=0;i<ur.count();i++)
	{
		UnigramRecord* rec = ur.getAt(i);

		if(ud.exactMatch(rec->key.c_str()) == rec->count){
			continue;
		}else{
			RETURN_FALSE;
		}
	}//end for

	RETURN_TRUE;
}

// 特殊短语字典的生成
PHP_FUNCTION(mmseg_gensynonyms)
{
	int argc = ZEND_NUM_ARGS();

	char *path = NULL;

	char *target = NULL;

#if PHP_MAJOR_VERSION < 7
	int path_len;
	int target_len;
#else
	size_t path_len;
	size_t target_len;
#endif

	zend_bool b_plainText = 0;

	if (zend_parse_parameters(argc TSRMLS_CC, "ss", &path, &path_len, &target, &target_len) == FAILURE)
		return;

	SynonymsDict dict;
	dict.import(path);
	if(target)
		dict.save(target);
	else
		dict.save("synonyms.dat");

	RETURN_TRUE;
}

// 同义词词典的生成
PHP_FUNCTION(mmseg_genthesaurus)
{
	int argc = ZEND_NUM_ARGS();

	char *path = NULL;

	char *target = NULL;

#if PHP_MAJOR_VERSION < 7
	int path_len;
	int target_len;
#else
	size_t path_len;
	size_t target_len;
#endif

	zend_bool b_plainText = 0;

	if (zend_parse_parameters(argc TSRMLS_CC, "ss", &path, &path_len, &target, &target_len) == FAILURE)
		return;

	ThesaurusDict tdict;
	tdict.import(path, target);
	RETURN_TRUE;
}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
<|endoftext|>


<commit_before>// bdls_processutil.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdls_processutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdls_processutil_cpp,"$Id$ $CSID$")

#include <bsls_assert.h>
#include <bsls_platform.h>

#include <bsl_algorithm.h>
#include <bsl_iostream.h>

#if !defined BSLS_PLATFORM_OS_WINDOWS
# include <unistd.h>    // getpid

# if defined BSLS_PLATFORM_OS_AIX
#   include <bslma_allocator.h>
#   include <bslma_deallocatorguard.h>
#   include <bslma_default.h>
#   include <bsl_algorithm.h>
#   include <sys/procfs.h>
#   include <sys/stat.h>
#   include <sys/types.h>
#   include <procinfo.h>
#   include <stdio.h>
# elif defined BSLS_PLATFORM_OS_CYGWIN
#   ifndef   _REENTRANT
#     define _REENTRANT
#   endif

#   include <bdlsb_memoutstreambuf.h>
#   include <bsl_fstream.h>
#   include <fcntl.h>
#   include <procfs.h>
# elif defined BSLS_PLATFORM_OS_DARWIN
#   include <bsl_algorithm.h>
#   include <libproc.h>
# elif defined BSLS_PLATFORM_OS_HPUX
#   include <sys/pstat.h>
# elif defined BSLS_PLATFORM_OS_LINUX
#   include <bslma_allocator.h>
#   include <bslma_deallocatorguard.h>
#   include <bslma_default.h>
#   include <bsls_types.h>
#   include <bsl_algorithm.h>
#   include <errno.h>
#   include <sys/stat.h>
#   include <sys/types.h>
# elif defined BSLS_PLATFORM_OS_SOLARIS
#   include <stdlib.h>
#   include <sys/stat.h>
#   include <sys/types.h>
#   include <stdio.h>
# else
#   error Unrecognized Platform
# endif
#else    // if defined BSLS_PLATFORM_OS_WINDOWS
# include <bdlde_charconvertutf16.h>
# include <bdlma_localsequentialallocator.h>
# include <windows.h>
#endif

namespace BloombergLP {
namespace bdls {
                             // ------------------
                             // struct ProcessUtil
                             // ------------------

// CLASS METHODS
int ProcessUtil::getProcessId()
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    return static_cast<int>(GetCurrentProcessId());
#else
    return static_cast<int>(::getpid());
#endif
}

int ProcessUtil::getProcessName(bsl::string *result)
{
    BSLS_ASSERT(result);

    result->clear();

#if defined BSLS_PLATFORM_OS_AIX
    struct procentry64  procbuffer;
    enum { k_BUF_LEN = 64 * 1024 };
    bslma::Allocator *allocator = bslma::Default::defaultAllocator();

    char *argsbuffer = static_cast<char *>(allocator->allocate(k_BUF_LEN));
    char *end = argsbuffer + k_BUF_LEN;
    bslma::DeallocatorGuard<bslma::Allocator> guard(argsbuffer, allocator);

    procbuffer.pi_pid = ProcessUtil::getProcessId();

    // '::getargs' should fill the beginning of 'argsbuffer' with
    // null-terminated 'argv[0]', which might be a relative path.

    if (0 == ::getargs(&procbuffer, sizeof(procbuffer), argsbuffer, k_BUF_LEN)
                                   && bsl::find(argsbuffer, end, '\0') < end) {
        result->assign(argsbuffer);
    }

    struct stat s;
    if (result->empty() ||
                   ('/' != (*result)[0] && 0 != ::stat(result->c_str(), &s))) {
        // Either 'getargs' failed, or the path is relative and the executable
        // is not there.  We have probably done a 'chdir' since program
        // start-up.  See if we can find the executable from "/proc".

        char fileNameBuf[50];
        snprintf(fileNameBuf,
                 sizeof(fileNameBuf),
                 "/proc/%d/object/a.out",
                 ProcessUtil::getProcessId());
        if (0 == ::stat(fileNameBuf, &s)) {
            result->assign(fileNameBuf);
        }
    }
#elif defined BSLS_PLATFORM_OS_CYGWIN
    enum { NUM_ELEMENTS = 14 + 16 };  // "/proc/<pid>/cmdline"

    bdlsb::MemOutStreamBuf osb(NUM_ELEMENTS);
    bsl::ostream           os(&osb);
    os << "/proc/" << ProcessUtil::getProcessId() << "/cmdline" << bsl::ends;
    const char *procfs = osb.data();

    bsl::ifstream ifs;
    ifs.open(procfs, bsl::ios_base::in | bsl::ios_base::binary);
    if (ifs.fail()) {
        return -1;                                                    // RETURN
    }
    ifs >> *result;

    bsl::string::size_type pos = result->find_first_of('\0');
    if (bsl::string::npos != pos) {
        result->resize(pos);
    }
#elif defined BSLS_PLATFORM_OS_DARWIN
    enum { k_BUF_LEN = 4 * 1024 };
    char buf[k_BUF_LEN];
    if (proc_pidpath(ProcessUtil::getProcessId(), buf, k_BUF_LEN) <= 0) {
        return -1;                                                    // RETURN
    }
    if (buf + k_BUF_LEN == bsl::find(buf + 0, buf + k_BUF_LEN, 0)) {
        return -1;                                                    // RETURN
    }

    result->assign(buf);
#elif defined BSLS_PLATFORM_OS_HPUX
    result->resize(1024);
    int rc = pstat_getcommandline(&(*result->begin()),
                                  result->size(),
                                  1,
                                  ProcessUtil::getProcessId());
    if (rc < 0) {
        return -1;                                                    // RETURN
    }

    bsl::string::size_type pos = result->find_first_of(' ');
    if (bsl::string::npos != pos) {
        result->resize(pos);
    }
#elif defined BSLS_PLATFORM_OS_LINUX
    // First, we attempt to get the executable name through the symlink
    // "/proc/self/exe", because, if successful, that will yield a full path
    // with symlinks resolved.

    const char linkName[] = { "/proc/self/exe" };
    struct stat s;
    bsls::Types::Int64 rc = ::lstat(linkName, &s);
    if (0 == rc && S_ISLNK(s.st_mode)) {
        enum { k_BUF_LEN = 64 * 1024 };
        bslma::Allocator *allocator = bslma::Default::defaultAllocator();

        char *linkBuf = static_cast<char *>(allocator->allocate(k_BUF_LEN));
        bslma::DeallocatorGuard<bslma::Allocator> guard(linkBuf, allocator);

        rc = ::readlink(linkName, linkBuf, k_BUF_LEN);
        if (0 < rc && rc < k_BUF_LEN && linkBuf + rc ==
                                     bsl::find(linkBuf, linkBuf + rc + 1, 0)) {
            result->assign(linkBuf);
        }
    }

    if (result->empty()) {
        // Reading the symlink failed, probably because "/proc" is sometimes
        // unavailable.  We fall back on reading '::program_invocation_name',
        // which will just yield 'argv[0]', which may or may not be a relative
        // path, a less optimal result.  Note that this can still cope with the
        // case where the path of the executable contains spaces.

        result->assign(::program_invocation_name);
    }
#elif defined BSLS_PLATFORM_OS_SOLARIS
    // '::getexecname' will return an absolute path with symlinks resolved.

    result->assign(::getexecname());
#elif defined BSLS_PLATFORM_OS_WINDOWS
    // On Windows, 'argv[0]' is always an absolute path, even if it was
    // specified on the cmd line as a relative path.  The following code yields
    // the full path.

    static const size_t k_INITIAL_SIZE = MAX_PATH + 1;
    bdlma::LocalSequentialAllocator<sizeof(wchar_t) * k_INITIAL_SIZE> la;
    bsl::wstring wResult(MAX_PATH, L'\0', &la);
    while (wResult.length() <= 4 * k_INITIAL_SIZE) {
        DWORD length = GetModuleFileNameW(0, &wResult[0], wResult.length());
        if (length == 0) {  // Error
            return 1;                                                 // RETURN
        }
        else if (length < wResult.length()) {  // Success
            wResult.resize(length);
            return bdlde::CharConvertUtf16::utf16ToUtf8(result, wResult);
                                                                      // RETURN
        }
        else { // Not enough space for the process name in 'wResult'
            wResult.resize(wResult.length() * 2); // Make more space
        }
    }

    return -1; // The path name is too long (more than 4 * k_INITIAL_SIZE)
#else
# error    Unrecognized Platform
#endif

    return result->empty();    // 'false' == 0 if success
}

}  // close package namespace
}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>bdls_processutil: slight enhancement of Darwin<commit_after>// bdls_processutil.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdls_processutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdls_processutil_cpp,"$Id$ $CSID$")

#include <bsls_assert.h>
#include <bsls_platform.h>

#include <bsl_algorithm.h>
#include <bsl_iostream.h>

#if !defined BSLS_PLATFORM_OS_WINDOWS
# include <unistd.h>    // getpid

# if defined BSLS_PLATFORM_OS_AIX
#   include <bslma_allocator.h>
#   include <bslma_deallocatorguard.h>
#   include <bslma_default.h>
#   include <bsl_algorithm.h>
#   include <sys/procfs.h>
#   include <sys/stat.h>
#   include <sys/types.h>
#   include <procinfo.h>
#   include <stdio.h>
# elif defined BSLS_PLATFORM_OS_CYGWIN
#   ifndef   _REENTRANT
#     define _REENTRANT
#   endif

#   include <bdlsb_memoutstreambuf.h>
#   include <bsl_fstream.h>
#   include <fcntl.h>
#   include <procfs.h>
# elif defined BSLS_PLATFORM_OS_DARWIN
#   include <bsl_algorithm.h>
#   include <libproc.h>
# elif defined BSLS_PLATFORM_OS_HPUX
#   include <sys/pstat.h>
# elif defined BSLS_PLATFORM_OS_LINUX
#   include <bslma_allocator.h>
#   include <bslma_deallocatorguard.h>
#   include <bslma_default.h>
#   include <bsls_types.h>
#   include <bsl_algorithm.h>
#   include <errno.h>
#   include <sys/stat.h>
#   include <sys/types.h>
# elif defined BSLS_PLATFORM_OS_SOLARIS
#   include <stdlib.h>
#   include <sys/stat.h>
#   include <sys/types.h>
#   include <stdio.h>
# else
#   error Unrecognized Platform
# endif
#else    // if defined BSLS_PLATFORM_OS_WINDOWS
# include <bdlde_charconvertutf16.h>
# include <bdlma_localsequentialallocator.h>
# include <windows.h>
#endif

namespace BloombergLP {
namespace bdls {
                             // ------------------
                             // struct ProcessUtil
                             // ------------------

// CLASS METHODS
int ProcessUtil::getProcessId()
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    return static_cast<int>(GetCurrentProcessId());
#else
    return static_cast<int>(::getpid());
#endif
}

int ProcessUtil::getProcessName(bsl::string *result)
{
    BSLS_ASSERT(result);

    result->clear();

#if defined BSLS_PLATFORM_OS_AIX
    struct procentry64  procbuffer;
    enum { k_BUF_LEN = 64 * 1024 };
    bslma::Allocator *allocator = bslma::Default::defaultAllocator();

    char *argsbuffer = static_cast<char *>(allocator->allocate(k_BUF_LEN));
    char *end = argsbuffer + k_BUF_LEN;
    bslma::DeallocatorGuard<bslma::Allocator> guard(argsbuffer, allocator);

    procbuffer.pi_pid = ProcessUtil::getProcessId();

    // '::getargs' should fill the beginning of 'argsbuffer' with
    // null-terminated 'argv[0]', which might be a relative path.

    if (0 == ::getargs(&procbuffer, sizeof(procbuffer), argsbuffer, k_BUF_LEN)
                                   && bsl::find(argsbuffer, end, '\0') < end) {
        result->assign(argsbuffer);
    }

    struct stat s;
    if (result->empty() ||
                   ('/' != (*result)[0] && 0 != ::stat(result->c_str(), &s))) {
        // Either 'getargs' failed, or the path is relative and the executable
        // is not there.  We have probably done a 'chdir' since program
        // start-up.  See if we can find the executable from "/proc".

        char fileNameBuf[50];
        snprintf(fileNameBuf,
                 sizeof(fileNameBuf),
                 "/proc/%d/object/a.out",
                 ProcessUtil::getProcessId());
        if (0 == ::stat(fileNameBuf, &s)) {
            result->assign(fileNameBuf);
        }
    }
#elif defined BSLS_PLATFORM_OS_CYGWIN
    enum { NUM_ELEMENTS = 14 + 16 };  // "/proc/<pid>/cmdline"

    bdlsb::MemOutStreamBuf osb(NUM_ELEMENTS);
    bsl::ostream           os(&osb);
    os << "/proc/" << ProcessUtil::getProcessId() << "/cmdline" << bsl::ends;
    const char *procfs = osb.data();

    bsl::ifstream ifs;
    ifs.open(procfs, bsl::ios_base::in | bsl::ios_base::binary);
    if (ifs.fail()) {
        return -1;                                                    // RETURN
    }
    ifs >> *result;

    bsl::string::size_type pos = result->find_first_of('\0');
    if (bsl::string::npos != pos) {
        result->resize(pos);
    }
#elif defined BSLS_PLATFORM_OS_DARWIN
    // We empirically determined that 'proc_pidpath' won't tolerate a buffer
    // much longer than 4K, and 4K is short enough not to be worth dynamically
    // allocating.

    enum { k_BUF_LEN = 4 * 1024 };
    char buf[k_BUF_LEN];
    bsl::fill(buf + 0, buf + k_BUF_LEN, '*');
    if (proc_pidpath(ProcessUtil::getProcessId(), buf, k_BUF_LEN) <= 0) {
        return -1;                                                    // RETURN
    }
    if (buf + k_BUF_LEN == bsl::find(buf + 0, buf + k_BUF_LEN, 0)) {
        return -1;                                                    // RETURN
    }

    result->assign(buf);
#elif defined BSLS_PLATFORM_OS_HPUX
    result->resize(1024);
    int rc = pstat_getcommandline(&(*result->begin()),
                                  result->size(),
                                  1,
                                  ProcessUtil::getProcessId());
    if (rc < 0) {
        return -1;                                                    // RETURN
    }

    bsl::string::size_type pos = result->find_first_of(' ');
    if (bsl::string::npos != pos) {
        result->resize(pos);
    }
#elif defined BSLS_PLATFORM_OS_LINUX
    // First, we attempt to get the executable name through the symlink
    // "/proc/self/exe", because, if successful, that will yield a full path
    // with symlinks resolved.

    const char linkName[] = { "/proc/self/exe" };
    struct stat s;
    bsls::Types::Int64 rc = ::lstat(linkName, &s);
    if (0 == rc && S_ISLNK(s.st_mode)) {
        enum { k_BUF_LEN = 64 * 1024 };
        bslma::Allocator *allocator = bslma::Default::defaultAllocator();

        char *linkBuf = static_cast<char *>(allocator->allocate(k_BUF_LEN));
        bslma::DeallocatorGuard<bslma::Allocator> guard(linkBuf, allocator);

        rc = ::readlink(linkName, linkBuf, k_BUF_LEN);
        if (0 < rc && rc < k_BUF_LEN && linkBuf + rc ==
                                     bsl::find(linkBuf, linkBuf + rc + 1, 0)) {
            result->assign(linkBuf);
        }
    }

    if (result->empty()) {
        // Reading the symlink failed, probably because "/proc" is sometimes
        // unavailable.  We fall back on reading '::program_invocation_name',
        // which will just yield 'argv[0]', which may or may not be a relative
        // path, a less optimal result.  Note that this can still cope with the
        // case where the path of the executable contains spaces.

        result->assign(::program_invocation_name);
    }
#elif defined BSLS_PLATFORM_OS_SOLARIS
    // '::getexecname' will return an absolute path with symlinks resolved.

    result->assign(::getexecname());
#elif defined BSLS_PLATFORM_OS_WINDOWS
    // On Windows, 'argv[0]' is always an absolute path, even if it was
    // specified on the cmd line as a relative path.  The following code yields
    // the full path.

    static const size_t k_INITIAL_SIZE = MAX_PATH + 1;
    bdlma::LocalSequentialAllocator<sizeof(wchar_t) * k_INITIAL_SIZE> la;
    bsl::wstring wResult(MAX_PATH, L'\0', &la);
    while (wResult.length() <= 4 * k_INITIAL_SIZE) {
        DWORD length = GetModuleFileNameW(0, &wResult[0], wResult.length());
        if (length == 0) {  // Error
            return 1;                                                 // RETURN
        }
        else if (length < wResult.length()) {  // Success
            wResult.resize(length);
            return bdlde::CharConvertUtf16::utf16ToUtf8(result, wResult);
                                                                      // RETURN
        }
        else { // Not enough space for the process name in 'wResult'
            wResult.resize(wResult.length() * 2); // Make more space
        }
    }

    return -1; // The path name is too long (more than 4 * k_INITIAL_SIZE)
#else
# error    Unrecognized Platform
#endif

    return result->empty();    // 'false' == 0 if success
}

}  // close package namespace
}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include <windows.h>

#define MAXWAIT 10000

bool insertDll(DWORD procID, std::string dll);
BOOL InjectDLL(DWORD dwProcessId, LPCSTR lpszDLLPath);
bool InjectDll(char *dllName, DWORD ProcessID);

void main( int argc, char* argv[] )
{
    InjectDLL( 6968, "c:\\src\\github\\Tagger\\playground\\HookSpy\\Debug\\HookSpyDll.dll" );
    //InjectDll( "c:\\Program Files (x86)\\totalcmd\\CABRK.DLL", 6968 );
}

bool GimmePrivileges(){
    HANDLE Token;
    TOKEN_PRIVILEGES tp;
    if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token)    )
    {
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL);
        return true;
    }
    return false;
}

BOOL InjectDLL(DWORD dwProcessId, LPCSTR lpszDLLPath)
{

    HANDLE  hProcess, hThread;
    LPVOID  lpBaseAddr, lpFuncAddr;
    DWORD   dwMemSize, dwExitCode;
    BOOL    bSuccess = FALSE;
    HMODULE hUserDLL;

    GimmePrivileges();

    if((hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION
        |PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwProcessId)))
    {
        dwMemSize = lstrlenA(lpszDLLPath) + 1;
        if(lpBaseAddr = VirtualAllocEx(hProcess, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE))
        {
            if(WriteProcessMemory(hProcess, lpBaseAddr, lpszDLLPath, dwMemSize, NULL))
            {
                if(hUserDLL = LoadLibrary(TEXT("kernel32.dll")))
                {
                    if(lpFuncAddr = GetProcAddress(hUserDLL, "LoadLibraryA"))
                    {
                        if(hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFuncAddr, lpBaseAddr, 0, NULL))
                        {
                            WaitForSingleObject(hThread, INFINITE);
                            if(GetExitCodeThread(hThread, &dwExitCode)) {
                                bSuccess = (dwExitCode != 0) ? TRUE : FALSE;
                            }
                            CloseHandle(hThread);
                        }
                    }
                    FreeLibrary(hUserDLL);
                }
            }
            VirtualFreeEx(hProcess, lpBaseAddr, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }

    return bSuccess;
}

bool InjectDll(char *dllName, DWORD ProcessID)
{
    if (!GimmePrivileges ())
    {
        printf ("Error elivating privileges \n");
        return false;
    }
    else
        printf ("Privileges elivated \n");
    //DWORD ProcessID = GetTargetProcessIdFromProcname (procName); //i didnt include this function because i know for a fact it works
    HANDLE Proc;
    HANDLE RemoteThread;
    char buf[50]={0};
    LPVOID RemoteString, LoadLibAddy;

    if(!ProcessID)
        return false;

    Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);

    if(!Proc)
    {
        printf("OpenProcess() failed: %d \n", GetLastError());
        return false;
    }

    LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");

    RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(dllName), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    if (!WriteProcessMemory(Proc, (LPVOID)RemoteString, dllName,strlen(dllName), NULL))
    {
        printf ("writeProcMem error: %d \n", GetLastError ());
        return false;
    }
    RemoteThread = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
    if (RemoteThread == NULL)
    {
        printf ("CreateRemoteThread error: %d \n", GetLastError());
        return false;
    }
    CloseHandle(Proc);

    return true;
}<commit_msg>All call to WinAPI functions report error on fail. Graceful resource cleanup is not implemented yet.<commit_after>#include <string>
#include <iostream>
#include <windows.h>
#include <conio.h>

using namespace std;

void AddDebugPrivilege();
void InjectDll( DWORD dwProcessId, LPCSTR lpszDLLPath );

void main( int argc, char* argv[] )
{
    cout << "Adding debug privilege to current process..." << endl;
    AddDebugPrivilege();

    int process = atoi( argv[1] );
    LPCSTR injectedDll = argv[2];
    cout << "Injecting dll: " << injectedDll << endl;
    cout << "To process ID: " << process << endl;
    InjectDll( process, injectedDll );

    cout << "Dll was successfully injected." << endl;
    _getch();
}

void AddDebugPrivilege()
{
    HANDLE token;
    HANDLE injector = GetCurrentProcess();
    TOKEN_PRIVILEGES privileges;

    if( 0 == OpenProcessToken( injector, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token ) )
    {
        cout << "OpenProcessToken failed with code: " << GetLastError() << endl;
        exit( 1 );
    }

    if( 0 == LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid ) )
    {
        cout << "LookupPrivilegeValue failed with code: " << GetLastError() << endl;
        exit( 1 );
    }

    privileges.PrivilegeCount = 1;
    privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if( 0 == AdjustTokenPrivileges( token, 0, &privileges, sizeof(privileges), NULL, NULL ) )
    {
        cout << "AdjustTokenPrivileges failed with code: " << GetLastError() << endl;
        exit( 1 );
    }
}

void InjectDll( DWORD processId, LPCSTR dllPath )
{
    HANDLE hProcess = OpenProcess(
        PROCESS_CREATE_THREAD|
        PROCESS_QUERY_INFORMATION|
        PROCESS_VM_OPERATION|
        PROCESS_VM_WRITE|
        PROCESS_VM_READ,
        FALSE,
        processId);
    if( NULL == hProcess )
    {
        cout << "OpenProcess failed with code: " << GetLastError() << endl;
        exit(1);
    }

    DWORD dwMemSize = lstrlenA(dllPath) + 1;
    LPVOID lpBaseAddr = VirtualAllocEx( hProcess, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE );
    if( NULL == lpBaseAddr )
    {
        cout << "VirtualAllocEx failed with code: " << GetLastError() << endl;
        exit(1);
    }

    BOOL memoryWriteSuccess = WriteProcessMemory( hProcess, lpBaseAddr, dllPath, dwMemSize, NULL );
    if( 0 == memoryWriteSuccess )
    {
        cout << "WriteProcessMemory failed with code: " << GetLastError() << endl;
        exit(1);
    }

    HMODULE hUserDLL = LoadLibrary( TEXT("kernel32.dll") );
    if( NULL == hUserDLL )
    {
        cout << "LoadLibrary failed with code: " << GetLastError() << endl;
        exit(1);
    }

    LPVOID lpFuncAddr = GetProcAddress( hUserDLL, "LoadLibraryA" );
    if( NULL == lpFuncAddr )
    {
        cout << "GetProcAddress failed with code: " << GetLastError() << endl;
        exit(1);
    }

    HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFuncAddr, lpBaseAddr, 0, NULL );
    if( NULL == hThread )
    {
        cout << "CreateRemoteThread failed with code: " << GetLastError() << endl;
        exit(1);
    }

    DWORD waitResult = WaitForSingleObject( hThread, INFINITE );
    if( WAIT_OBJECT_0 != waitResult )
    {
        cout << "WaitForSingleObject failed. Status: " << waitResult << ". Last error: " << GetLastError() << endl;
        exit(1);
    }

    DWORD dwExitCode;
    BOOL exitThreadResult = GetExitCodeThread( hThread, &dwExitCode );
    if( 0 == exitThreadResult )
    {
        cout << "GetExitCodeThread failed with code: " << GetLastError() << endl;
        exit(1);
    }

    if( 0 == dwExitCode )
    {
        cout << "Remote LoadLibrary failed with code: " << GetLastError() << endl;
        exit(1);
    }

    CloseHandle( hThread );
    FreeLibrary( hUserDLL );
    VirtualFreeEx( hProcess, lpBaseAddr, 0, MEM_RELEASE );
    CloseHandle( hProcess );
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * 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 <QLabel>
#include <QVBoxLayout>

#include "intropage.h"

IntroPage::IntroPage()
{
    setTitle(tr("Introduction"));
    setSubTitle(tr("Welcome to NitroShare"));

    QLabel *label = new QLabel(tr(
        "Thank you for installing NitroShare!\n\nThe application is designed "
        "to make transferring information between devices as simple as "
        "possible. Here are just some of the features included:\n\n"
        "\u2022 Automatic peer discovery\n"
        "\u2022 Extremely fast file transfers\n"
        "\u2022 Compatibility with all major platforms\n\n"
        "This wizard will guide you through the initial setup process to help "
        "ensure NitroShare works exactly the way you want it to."

    ));
    label->setWordWrap(true);

    QVBoxLayout *vboxLayout = new QVBoxLayout;
    vboxLayout->addWidget(label);
    setLayout(vboxLayout);
}
<commit_msg>Replace Unicode characters that do not display correctly on Windows.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * 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 <QLabel>
#include <QVBoxLayout>

#include "intropage.h"

IntroPage::IntroPage()
{
    setTitle(tr("Introduction"));
    setSubTitle(tr("Welcome to NitroShare"));

    QLabel *label = new QLabel(tr(
        "Thank you for installing NitroShare!\n\nThe application is designed "
        "to make transferring information between devices as simple as "
        "possible. Here are just some of the features included:\n\n"
        "- Automatic peer discovery\n"
        "- Extremely fast file transfers\n"
        "- Compatibility with all major platforms\n\n"
        "This wizard will guide you through the initial setup process to help "
        "ensure NitroShare works exactly the way you want it to."

    ));
    label->setWordWrap(true);

    QVBoxLayout *vboxLayout = new QVBoxLayout;
    vboxLayout->addWidget(label);
    setLayout(vboxLayout);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "vbucket.hh"
#include "ep_engine.h"
#include "ep.hh"
#include "backfill.hh"

static bool isMemoryUsageTooHigh(EPStats &stats) {
    double currentSize = static_cast<double>(stats.currentSize.get() + stats.memOverhead.get());
    double maxSize = static_cast<double>(stats.maxDataSize.get());
    return currentSize > (maxSize * BACKFILL_MEM_THRESHOLD);
}

/**
 * Callback class used to process an item backfilled from disk and push it into
 * the corresponding TAP queue.
 */
class BackfillDiskCallback : public Callback<GetValue> {
public:
    BackfillDiskCallback(const std::string &n, TapConnMap &tcm, EventuallyPersistentEngine* e)
        : tapConnName(n), connMap(tcm), engine(e) {
        assert(engine);
    }

    void callback(GetValue &val);

private:

    const std::string           tapConnName;
    TapConnMap                 &connMap;
    EventuallyPersistentEngine *engine;
};

void BackfillDiskCallback::callback(GetValue &gv) {
    ReceivedItemTapOperation tapop(true);
    // if the tap connection is closed, then free an Item instance
    if (!connMap.performTapOp(tapConnName, tapop, gv.getValue())) {
        delete gv.getValue();
    }

    NotifyPausedTapOperation notifyOp;
    connMap.performTapOp(tapConnName, notifyOp, engine);
}

bool BackfillDiskLoad::callback(Dispatcher &d, TaskId t) {
    bool valid = false;

    if (isMemoryUsageTooHigh(engine->getEpStats())) {
        getLogger()->log(EXTENSION_LOG_INFO, NULL,
                         "VBucket %d backfill task from disk is temporarily suspended "
                         "because the current memory usage is too high.\n",
                         vbucket);
        d.snooze(t, 1);
        return true;
    }

    if (connMap.checkConnectivity(name) && !engine->getEpStore()->isFlushAllScheduled()) {
        shared_ptr<Callback<GetValue> > backfill_cb(new BackfillDiskCallback(name, connMap, engine));
        store->dump(vbucket, backfill_cb);
        valid = true;
    }

    getLogger()->log(EXTENSION_LOG_INFO, NULL,
                     "VBucket %d backfill task from disk is completed.\n",
                     vbucket);

    // Should decr the disk backfill counter regardless of the connectivity status
    CompleteDiskBackfillTapOperation op;
    connMap.performTapOp(name, op, static_cast<void*>(NULL));

    if (valid && connMap.checkBackfillCompletion(name)) {
        engine->notifyNotificationThread();
    }

    return false;
}

std::string BackfillDiskLoad::description() {
    std::stringstream rv;
    rv << "Loading TAP backfill from disk for vb " << vbucket;
    return rv.str();
}

bool BackFillVisitor::visitBucket(RCPtr<VBucket> &vb) {
    apply();

    if (vBucketFilter(vb->getId())) {
        VBucketVisitor::visitBucket(vb);
        // If the current resident ratio for a given vbucket is below the resident threshold
        // for memory backfill only, schedule the disk backfill for more efficient bg fetches.
        double numItems = static_cast<double>(vb->ht.getNumItems());
        double numNonResident = static_cast<double>(vb->ht.getNumNonResidentItems());
        if (numItems == 0) {
            return true;
        }

        double residentThreshold = engine->getTapConfig().getBackfillResidentThreshold();
        residentRatioBelowThreshold =
            ((numItems - numNonResident) / numItems) < residentThreshold ? true : false;
        if (efficientVBDump && residentRatioBelowThreshold) {
            vbuckets.push_back(vb->getId());
            ScheduleDiskBackfillTapOperation tapop;
            engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
        }
        // When the backfill is scheduled for a given vbucket, set the TAP cursor to
        // the beginning of the open checkpoint.
        engine->tapConnMap->SetCursorToOpenCheckpoint(name, vb->getId());
        return true;
    }
    return false;
}

void BackFillVisitor::visit(StoredValue *v) {
    // If efficient VBdump is supported and an item is not resident,
    // skip the item as it will be fetched by the disk backfill.
    if (efficientVBDump && residentRatioBelowThreshold && !v->isResident()) {
        return;
    }
    std::string k = v->getKey();
    queued_item qi(new QueuedItem(k, currentBucket->getId(), queue_op_set,
                                  -1, v->getId()));
    uint16_t shardId = engine->kvstore->getShardId(*qi);
    found.push_back(std::make_pair(shardId, qi));
}

void BackFillVisitor::apply(void) {
    // If efficient VBdump is supported, schedule all the disk backfill tasks.
    if (efficientVBDump) {
        std::vector<uint16_t>::iterator it = vbuckets.begin();
        for (; it != vbuckets.end(); it++) {
            Dispatcher *d(engine->epstore->getRODispatcher());
            KVStore *underlying(engine->epstore->getROUnderlying());
            assert(d);
            getLogger()->log(EXTENSION_LOG_INFO, NULL,
                             "Schedule a full backfill from disk for vbucket %d.\n",
                              *it);
            shared_ptr<DispatcherCallback> cb(new BackfillDiskLoad(name,
                                                                   engine,
                                                                   *engine->tapConnMap,
                                                                   underlying,
                                                                   *it,
                                                                   validityToken));
            d->schedule(cb, NULL, Priority::TapBgFetcherPriority);
        }
        vbuckets.clear();
    }

    setEvents();
}

void BackFillVisitor::setEvents() {
    if (checkValidity()) {
        if (!found.empty()) {
            // Don't notify unless we've got some data..
            TaggedQueuedItemComparator<uint16_t> comparator;
            std::sort(found.begin(), found.end(), comparator);

            std::vector<std::pair<uint16_t, queued_item> >::iterator it(found.begin());
            for (; it != found.end(); ++it) {
                queue->push_back(it->second);
            }
            found.clear();
            engine->tapConnMap->setEvents(name, queue);
        }
    }
}

bool BackFillVisitor::pauseVisitor() {
    bool pause(true);

    ssize_t theSize(engine->tapConnMap->backfillQueueDepth(name));
    if (!checkValidity() || theSize < 0) {
        getLogger()->log(EXTENSION_LOG_WARNING, NULL,
                         "TapProducer %s went away.  Stopping backfill.\n",
                         name.c_str());
        valid = false;
        return false;
    }

    ssize_t maxBackfillSize = engine->getTapConfig().getBackfillBacklogLimit();
    pause = theSize > maxBackfillSize || isMemoryUsageTooHigh(engine->getEpStats());

    if (pause) {
        getLogger()->log(EXTENSION_LOG_INFO, NULL,
                         "Tap queue depth is too big for %s or memory usage too high, "
                         "Pausing temporarily...\n",
                         name.c_str());
    }
    return pause;
}

void BackFillVisitor::complete() {
    apply();
    CompleteBackfillTapOperation tapop;
    engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
    if (engine->tapConnMap->checkBackfillCompletion(name)) {
        engine->notifyNotificationThread();
    }
    getLogger()->log(EXTENSION_LOG_INFO, NULL,
                     "Backfill dispatcher task for TapProducer %s is completed.\n",
                     name.c_str());
}

bool BackFillVisitor::checkValidity() {
    if (valid) {
        valid = engine->tapConnMap->checkConnectivity(name);
        if (!valid) {
            getLogger()->log(EXTENSION_LOG_WARNING, NULL,
                             "Backfilling connectivity for %s went invalid. "
                             "Stopping backfill.\n",
                             name.c_str());
        }
    }
    return valid;
}

bool BackfillTask::callback(Dispatcher &d, TaskId t) {
    (void) t;
    epstore->visit(bfv, "Backfill task", &d, Priority::BackfillTaskPriority, true, 1);
    return false;
}
<commit_msg>Remove duplicate memory constraint checks on backfill.<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "vbucket.hh"
#include "ep_engine.h"
#include "ep.hh"
#include "backfill.hh"

static bool isMemoryUsageTooHigh(EPStats &stats) {
    double currentSize = static_cast<double>(stats.currentSize.get() + stats.memOverhead.get());
    double maxSize = static_cast<double>(stats.maxDataSize.get());
    return currentSize > (maxSize * BACKFILL_MEM_THRESHOLD);
}

/**
 * Callback class used to process an item backfilled from disk and push it into
 * the corresponding TAP queue.
 */
class BackfillDiskCallback : public Callback<GetValue> {
public:
    BackfillDiskCallback(const std::string &n, TapConnMap &tcm, EventuallyPersistentEngine* e)
        : tapConnName(n), connMap(tcm), engine(e) {
        assert(engine);
    }

    void callback(GetValue &val);

private:

    const std::string           tapConnName;
    TapConnMap                 &connMap;
    EventuallyPersistentEngine *engine;
};

void BackfillDiskCallback::callback(GetValue &gv) {
    ReceivedItemTapOperation tapop(true);
    // if the tap connection is closed, then free an Item instance
    if (!connMap.performTapOp(tapConnName, tapop, gv.getValue())) {
        delete gv.getValue();
    }

    NotifyPausedTapOperation notifyOp;
    connMap.performTapOp(tapConnName, notifyOp, engine);
}

bool BackfillDiskLoad::callback(Dispatcher &, TaskId) {
    bool valid = false;

    if (connMap.checkConnectivity(name) && !engine->getEpStore()->isFlushAllScheduled()) {
        shared_ptr<Callback<GetValue> > backfill_cb(new BackfillDiskCallback(name, connMap, engine));
        store->dump(vbucket, backfill_cb);
        valid = true;
    }

    getLogger()->log(EXTENSION_LOG_INFO, NULL,
                     "VBucket %d backfill task from disk is completed.\n",
                     vbucket);

    // Should decr the disk backfill counter regardless of the connectivity status
    CompleteDiskBackfillTapOperation op;
    connMap.performTapOp(name, op, static_cast<void*>(NULL));

    if (valid && connMap.checkBackfillCompletion(name)) {
        engine->notifyNotificationThread();
    }

    return false;
}

std::string BackfillDiskLoad::description() {
    std::stringstream rv;
    rv << "Loading TAP backfill from disk for vb " << vbucket;
    return rv.str();
}

bool BackFillVisitor::visitBucket(RCPtr<VBucket> &vb) {
    apply();

    if (vBucketFilter(vb->getId())) {
        VBucketVisitor::visitBucket(vb);
        // If the current resident ratio for a given vbucket is below the resident threshold
        // for memory backfill only, schedule the disk backfill for more efficient bg fetches.
        double numItems = static_cast<double>(vb->ht.getNumItems());
        double numNonResident = static_cast<double>(vb->ht.getNumNonResidentItems());
        if (numItems == 0) {
            return true;
        }

        double residentThreshold = engine->getTapConfig().getBackfillResidentThreshold();
        residentRatioBelowThreshold =
            ((numItems - numNonResident) / numItems) < residentThreshold ? true : false;
        if (efficientVBDump && residentRatioBelowThreshold) {
            vbuckets.push_back(vb->getId());
            ScheduleDiskBackfillTapOperation tapop;
            engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
        }
        // When the backfill is scheduled for a given vbucket, set the TAP cursor to
        // the beginning of the open checkpoint.
        engine->tapConnMap->SetCursorToOpenCheckpoint(name, vb->getId());
        return true;
    }
    return false;
}

void BackFillVisitor::visit(StoredValue *v) {
    // If efficient VBdump is supported and an item is not resident,
    // skip the item as it will be fetched by the disk backfill.
    if (efficientVBDump && residentRatioBelowThreshold && !v->isResident()) {
        return;
    }
    std::string k = v->getKey();
    queued_item qi(new QueuedItem(k, currentBucket->getId(), queue_op_set,
                                  -1, v->getId()));
    uint16_t shardId = engine->kvstore->getShardId(*qi);
    found.push_back(std::make_pair(shardId, qi));
}

void BackFillVisitor::apply(void) {
    // If efficient VBdump is supported, schedule all the disk backfill tasks.
    if (efficientVBDump) {
        std::vector<uint16_t>::iterator it = vbuckets.begin();
        for (; it != vbuckets.end(); it++) {
            Dispatcher *d(engine->epstore->getRODispatcher());
            KVStore *underlying(engine->epstore->getROUnderlying());
            assert(d);
            getLogger()->log(EXTENSION_LOG_INFO, NULL,
                             "Schedule a full backfill from disk for vbucket %d.\n",
                              *it);
            shared_ptr<DispatcherCallback> cb(new BackfillDiskLoad(name,
                                                                   engine,
                                                                   *engine->tapConnMap,
                                                                   underlying,
                                                                   *it,
                                                                   validityToken));
            d->schedule(cb, NULL, Priority::TapBgFetcherPriority);
        }
        vbuckets.clear();
    }

    setEvents();
}

void BackFillVisitor::setEvents() {
    if (checkValidity()) {
        if (!found.empty()) {
            // Don't notify unless we've got some data..
            TaggedQueuedItemComparator<uint16_t> comparator;
            std::sort(found.begin(), found.end(), comparator);

            std::vector<std::pair<uint16_t, queued_item> >::iterator it(found.begin());
            for (; it != found.end(); ++it) {
                queue->push_back(it->second);
            }
            found.clear();
            engine->tapConnMap->setEvents(name, queue);
        }
    }
}

bool BackFillVisitor::pauseVisitor() {
    bool pause(true);

    ssize_t theSize(engine->tapConnMap->backfillQueueDepth(name));
    if (!checkValidity() || theSize < 0) {
        getLogger()->log(EXTENSION_LOG_WARNING, NULL,
                         "TapProducer %s went away.  Stopping backfill.\n",
                         name.c_str());
        valid = false;
        return false;
    }

    ssize_t maxBackfillSize = engine->getTapConfig().getBackfillBacklogLimit();
    pause = theSize > maxBackfillSize || isMemoryUsageTooHigh(engine->getEpStats());

    if (pause) {
        getLogger()->log(EXTENSION_LOG_INFO, NULL,
                         "Tap queue depth is too big for %s or memory usage too high, "
                         "Pausing temporarily...\n",
                         name.c_str());
    }
    return pause;
}

void BackFillVisitor::complete() {
    apply();
    CompleteBackfillTapOperation tapop;
    engine->tapConnMap->performTapOp(name, tapop, static_cast<void*>(NULL));
    if (engine->tapConnMap->checkBackfillCompletion(name)) {
        engine->notifyNotificationThread();
    }
    getLogger()->log(EXTENSION_LOG_INFO, NULL,
                     "Backfill dispatcher task for TapProducer %s is completed.\n",
                     name.c_str());
}

bool BackFillVisitor::checkValidity() {
    if (valid) {
        valid = engine->tapConnMap->checkConnectivity(name);
        if (!valid) {
            getLogger()->log(EXTENSION_LOG_WARNING, NULL,
                             "Backfilling connectivity for %s went invalid. "
                             "Stopping backfill.\n",
                             name.c_str());
        }
    }
    return valid;
}

bool BackfillTask::callback(Dispatcher &d, TaskId t) {
    (void) t;
    epstore->visit(bfv, "Backfill task", &d, Priority::BackfillTaskPriority, true, 1);
    return false;
}
<|endoftext|>


<commit_before>#include "gimbal_impl.h"
#include "global_include.h"
#include <functional>

namespace dronecode_sdk {

GimbalImpl::GimbalImpl(System &system) : PluginImplBase(system)
{
    _parent->register_plugin(this);
}

GimbalImpl::~GimbalImpl()
{
    _parent->unregister_plugin(this);
}

void GimbalImpl::init() {}

void GimbalImpl::deinit() {}

void GimbalImpl::enable() {}

void GimbalImpl::disable() {}

Gimbal::Result GimbalImpl::set_pitch_and_yaw(float pitch_deg, float yaw_deg)
{
    const float roll_deg = 0.0f;
    MAVLinkCommands::CommandLong command{};

    command.command = MAV_CMD_DO_MOUNT_CONTROL;
    command.params.param1 = pitch_deg;
    command.params.param2 = roll_deg;
    command.params.param3 = yaw_deg;
    command.params.param7 = float(MAV_MOUNT_MODE_MAVLINK_TARGETING);
    command.target_component_id = _parent->get_autopilot_id();

    return gimbal_result_from_command_result(_parent->send_command(command));
}

void GimbalImpl::set_pitch_and_yaw_async(float pitch_deg,
                                         float yaw_deg,
                                         Gimbal::result_callback_t callback)
{
    const float roll_deg = 0.0f;
    MAVLinkCommands::CommandLong command{};

    command.command = MAV_CMD_DO_MOUNT_CONTROL;
    command.params.param1 = pitch_deg;
    command.params.param2 = roll_deg;
    command.params.param3 = yaw_deg;
    command.params.param7 = float(MAV_MOUNT_MODE_MAVLINK_TARGETING);
    command.target_component_id = _parent->get_autopilot_id();

    _parent->send_command_async(
        command, std::bind(&GimbalImpl::receive_command_result, std::placeholders::_1, callback));
}

Gimbal::Result
GimbalImpl::set_roi_location(double latitude_deg, double longitude_deg, float altitude_m)
{
    MAVLinkCommands::CommandInt command{};

    command.command = MAV_CMD_DO_SET_ROI_LOCATION;
    command.params.x = int32_t(latitude_deg * 1e7);
    command.params.y = int32_t(longitude_deg * 1e7);
    command.params.z = altitude_m;
    command.target_component_id = _parent->get_autopilot_id();

    return gimbal_result_from_command_result(_parent->send_command(command));
}

void GimbalImpl::set_roi_location_async(double latitude_deg,
                                        double longitude_deg,
                                        float altitude_m,
                                        Gimbal::result_callback_t callback)
{
    MAVLinkCommands::CommandInt command{};

    command.command = MAV_CMD_DO_SET_ROI_LOCATION;
    command.params.x = int32_t(latitude_deg * 1e7);
    command.params.y = int32_t(longitude_deg * 1e7);
    command.params.z = altitude_m;
    command.target_component_id = _parent->get_autopilot_id();

    _parent->send_command_async(
        command, std::bind(&GimbalImpl::receive_command_result, std::placeholders::_1, callback));
}

void GimbalImpl::receive_command_result(MAVLinkCommands::Result command_result,
                                        const Gimbal::result_callback_t &callback)
{
    Gimbal::Result gimbal_result = gimbal_result_from_command_result(command_result);

    if (callback) {
        callback(gimbal_result);
    }
}

Gimbal::Result GimbalImpl::gimbal_result_from_command_result(MAVLinkCommands::Result command_result)
{
    switch (command_result) {
        case MAVLinkCommands::Result::SUCCESS:
            return Gimbal::Result::SUCCESS;
        case MAVLinkCommands::Result::TIMEOUT:
            return Gimbal::Result::TIMEOUT;
        case MAVLinkCommands::Result::NO_SYSTEM:
        case MAVLinkCommands::Result::CONNECTION_ERROR:
        case MAVLinkCommands::Result::BUSY:
        case MAVLinkCommands::Result::COMMAND_DENIED:
        default:
            return Gimbal::Result::ERROR;
    }
}

} // namespace dronecode_sdk
<commit_msg>gimbal: fix rounding<commit_after>#include "gimbal_impl.h"
#include "global_include.h"
#include <functional>
#include <cmath>

namespace dronecode_sdk {

GimbalImpl::GimbalImpl(System &system) : PluginImplBase(system)
{
    _parent->register_plugin(this);
}

GimbalImpl::~GimbalImpl()
{
    _parent->unregister_plugin(this);
}

void GimbalImpl::init() {}

void GimbalImpl::deinit() {}

void GimbalImpl::enable() {}

void GimbalImpl::disable() {}

Gimbal::Result GimbalImpl::set_pitch_and_yaw(float pitch_deg, float yaw_deg)
{
    const float roll_deg = 0.0f;
    MAVLinkCommands::CommandLong command{};

    command.command = MAV_CMD_DO_MOUNT_CONTROL;
    command.params.param1 = pitch_deg;
    command.params.param2 = roll_deg;
    command.params.param3 = yaw_deg;
    command.params.param7 = float(MAV_MOUNT_MODE_MAVLINK_TARGETING);
    command.target_component_id = _parent->get_autopilot_id();

    return gimbal_result_from_command_result(_parent->send_command(command));
}

void GimbalImpl::set_pitch_and_yaw_async(float pitch_deg,
                                         float yaw_deg,
                                         Gimbal::result_callback_t callback)
{
    const float roll_deg = 0.0f;
    MAVLinkCommands::CommandLong command{};

    command.command = MAV_CMD_DO_MOUNT_CONTROL;
    command.params.param1 = pitch_deg;
    command.params.param2 = roll_deg;
    command.params.param3 = yaw_deg;
    command.params.param7 = float(MAV_MOUNT_MODE_MAVLINK_TARGETING);
    command.target_component_id = _parent->get_autopilot_id();

    _parent->send_command_async(
        command, std::bind(&GimbalImpl::receive_command_result, std::placeholders::_1, callback));
}

Gimbal::Result
GimbalImpl::set_roi_location(double latitude_deg, double longitude_deg, float altitude_m)
{
    MAVLinkCommands::CommandInt command{};

    command.command = MAV_CMD_DO_SET_ROI_LOCATION;
    command.params.x = int32_t(std::round(latitude_deg * 1e7));
    command.params.y = int32_t(std::round(longitude_deg * 1e7));
    command.params.z = altitude_m;
    command.target_component_id = _parent->get_autopilot_id();

    return gimbal_result_from_command_result(_parent->send_command(command));
}

void GimbalImpl::set_roi_location_async(double latitude_deg,
                                        double longitude_deg,
                                        float altitude_m,
                                        Gimbal::result_callback_t callback)
{
    MAVLinkCommands::CommandInt command{};

    command.command = MAV_CMD_DO_SET_ROI_LOCATION;
    command.params.x = int32_t(std::round(latitude_deg * 1e7));
    command.params.y = int32_t(std::round(longitude_deg * 1e7));
    command.params.z = altitude_m;
    command.target_component_id = _parent->get_autopilot_id();

    _parent->send_command_async(
        command, std::bind(&GimbalImpl::receive_command_result, std::placeholders::_1, callback));
}

void GimbalImpl::receive_command_result(MAVLinkCommands::Result command_result,
                                        const Gimbal::result_callback_t &callback)
{
    Gimbal::Result gimbal_result = gimbal_result_from_command_result(command_result);

    if (callback) {
        callback(gimbal_result);
    }
}

Gimbal::Result GimbalImpl::gimbal_result_from_command_result(MAVLinkCommands::Result command_result)
{
    switch (command_result) {
        case MAVLinkCommands::Result::SUCCESS:
            return Gimbal::Result::SUCCESS;
        case MAVLinkCommands::Result::TIMEOUT:
            return Gimbal::Result::TIMEOUT;
        case MAVLinkCommands::Result::NO_SYSTEM:
        case MAVLinkCommands::Result::CONNECTION_ERROR:
        case MAVLinkCommands::Result::BUSY:
        case MAVLinkCommands::Result::COMMAND_DENIED:
        default:
            return Gimbal::Result::ERROR;
    }
}

} // namespace dronecode_sdk
<|endoftext|>


<commit_before>#include "lodmaker.h"

struct QVertex {
	aten::vertex v;
	uint32_t idx;
	uint32_t grid[3];
	uint64_t hash;

	QVertex() {}

	QVertex(
		aten::vertex _v,
		uint32_t i,
		uint64_t h,
		uint32_t gx, uint32_t gy, uint32_t gz)
		: v(_v), idx(i), hash(h)
	{
		grid[0] = gx;
		grid[1] = gy;
		grid[2] = gz;
	}

	const QVertex& operator=(const QVertex& rhs)
	{
		v = rhs.v;
		idx = rhs.idx;
		grid[0] = rhs.grid[0];
		grid[1] = rhs.grid[1];
		grid[2] = rhs.grid[2];
		hash = rhs.hash;
	}
};

// NOTE
// gridX * gridY * gridZ  uint64_t 𒴂Ȃ悤ɂ

using qit = std::vector<QVertex>::iterator;

static void computeAverage(qit start, qit end)
{
	aten::vec3 pos(start->v.pos);
	aten::vec3 nml(start->v.nml);
	aten::vec3 uv(start->v.uv);

	uint32_t cnt = 1;

	for (auto q = start + 1; q != end; q++) {
		pos += q->v.pos;
		nml += q->v.nml;
		uv += q->v.uv;

		cnt++;
	}

	real div = real(1) / cnt;

	pos *= div;
	nml *= div;
	uv *= div;

	nml = normalize(nml);

	// vZʂ߂...
	for (auto q = start; q != end; q++) {
		q->v.pos = pos;
		q->v.nml = nml;
		q->v.uv = uv;
	}
}

void LodMaker::make(
	std::vector<aten::vertex>& dstVertices,
	std::vector<std::vector<int>>& dstIndices,
	const aten::aabb& bound,
	const std::vector<aten::vertex>& vertices,
	const std::vector<std::vector<aten::face*>>& triGroups,
	int gridX,
	int gridY,
	int gridZ)
{
	auto bmin = bound.minPos();
	auto range = bound.size();

	aten::vec3 scale(
		(gridX - 1) / range.x,
		(gridY - 1) / range.y,
		(gridZ - 1) / range.z);

	std::vector<std::vector<QVertex>> qvtxs(triGroups.size());
	std::vector<std::vector<uint32_t>> sortedIndices(triGroups.size());

	for (uint32_t i = 0; i < triGroups.size(); i++) {
		const auto tris = triGroups[i];

		qvtxs[i].reserve(tris.size());

		for (uint32_t n = 0; n < tris.size(); n++) {
			const auto tri = tris[n];

			for (int t = 0; t < 3; t++) {
				uint32_t idx = tri->param.idx[t];
				const auto& v = vertices[idx];

				auto grid = ((aten::vec3)v.pos - bmin) * scale + real(0.5);

				uint32_t gx = (uint32_t)grid.x;
				uint32_t gy = (uint32_t)grid.y;
				uint32_t gz = (uint32_t)grid.z;

				uint64_t hash = gz * (gridX * gridY) + gy * gridX + gx;

				qvtxs[i].push_back(QVertex(v, idx, hash, gx, gy, gz));
			}
		}
	}

	// ObhɓĂ钸_̏ɂȂ悤Ƀ\[g.

	for (uint32_t i = 0; i < qvtxs.size(); i++)
	{
		std::sort(
			qvtxs[i].begin(), qvtxs[i].end(),
			[](const QVertex& q0, const QVertex& q1)
		{
			return q0.hash > q1.hash;
		});

		sortedIndices.reserve(triGroups[i].size());

		uint32_t num = (uint32_t)qvtxs[i].size();

		// CfbNX_ɂ킹ĕבւ.
		for (uint32_t n = 0; n < num; n++) {
			const auto& q = qvtxs[i][n];

			// X̃CfbNẌʒuɐVCfbNXl.
			sortedIndices[i][q.idx] = n;
		}
	}

	// ObhɓĂ钸_̕ϒlvZāAP̒_ɂĂ܂.
	// UV͕邪AFZJ_oEXɎĝŁA͋CɂȂ.

	for (uint32_t i = 0; i < qvtxs.size(); i++)
	{
		auto start = qvtxs[i].begin();

		while (start != qvtxs[i].end())
		{
			auto end = start;

			// ObhقȂ钸_ɂȂ܂ŒT.
			while (end != qvtxs[i].end() && start->hash == end->hash) {
				end++;
			}

			// TODO
			// όvZ.
			computeAverage(start, end);

			for (auto q = start; q != end; q++) {
				if (q == start) {
					dstVertices.push_back(q->v);
				}
				else {
					// قȂʒu̓_̏ꍇ.

					// O̓_Ɣr.
					auto prev = q - 1;

					auto v0 = q->v.pos;
					auto v1 = prev->v.pos;

					bool isEqual = (memcmp(&v0, &v1, sizeof(v0)) == 0);

					if (!isEqual) {
						dstVertices.push_back(q->v);
					}
				}

				// CfbNXXV.
				q->idx = (uint32_t)dstVertices.size() - 1;
			}

			// ̊JnʒuXV
			start = end;
		}
	}

	// LODꂽʂ̃CfbNXi[.

	dstIndices.resize(triGroups.size());

	for (uint32_t i = 0; i < triGroups.size(); i++) {
		const auto tris = triGroups[i];

		dstIndices[i].reserve(tris.size() * 3);

		for (uint32_t n = 0; n < tris.size(); n++) {
			const auto tri = tris[n];

			for (int t = 0; t < 3; t++) {
				uint32_t idx = tri->param.idx[t];

				auto sortedIdx = sortedIndices[i][idx];
				auto newIdx = qvtxs[i][sortedIdx].idx;

				dstIndices[i].push_back(newIdx);
			}
		}
	}
}
<commit_msg>Fux build errors.<commit_after>#include "lodmaker.h"

struct QVertex {
	aten::vertex v;
	uint32_t idx;
	uint32_t grid[3];
	uint64_t hash;

	QVertex() {}

	QVertex(
		aten::vertex _v,
		uint32_t i,
		uint64_t h,
		uint32_t gx, uint32_t gy, uint32_t gz)
		: v(_v), idx(i), hash(h)
	{
		grid[0] = gx;
		grid[1] = gy;
		grid[2] = gz;
	}

	const QVertex& operator=(const QVertex& rhs)
	{
		v = rhs.v;
		idx = rhs.idx;
		grid[0] = rhs.grid[0];
		grid[1] = rhs.grid[1];
		grid[2] = rhs.grid[2];
		hash = rhs.hash;

		return *this;
	}
};

// NOTE
// gridX * gridY * gridZ  uint64_t 𒴂Ȃ悤ɂ

using qit = std::vector<QVertex>::iterator;

static void computeAverage(qit start, qit end)
{
	aten::vec4 pos(start->v.pos);
	aten::vec3 nml(start->v.nml);
	aten::vec3 uv(start->v.uv);

	uint32_t cnt = 1;

	for (auto q = start + 1; q != end; q++) {
		pos += q->v.pos;
		nml += q->v.nml;
		uv += q->v.uv;

		cnt++;
	}

	real div = real(1) / cnt;

	pos *= div;
	nml *= div;
	uv *= div;

	pos.w = real(1);
	nml = normalize(nml);

	// vZʂ߂...
	for (auto q = start; q != end; q++) {
		q->v.pos = pos;
		q->v.nml = nml;
		q->v.uv = uv;
	}
}

void LodMaker::make(
	std::vector<aten::vertex>& dstVertices,
	std::vector<std::vector<int>>& dstIndices,
	const aten::aabb& bound,
	const std::vector<aten::vertex>& vertices,
	const std::vector<std::vector<aten::face*>>& triGroups,
	int gridX,
	int gridY,
	int gridZ)
{
	auto bmin = bound.minPos();
	auto range = bound.size();

	aten::vec3 scale(
		(gridX - 1) / range.x,
		(gridY - 1) / range.y,
		(gridZ - 1) / range.z);

	std::vector<std::vector<QVertex>> qvtxs(triGroups.size());
	std::vector<std::vector<uint32_t>> sortedIndices(triGroups.size());

	for (uint32_t i = 0; i < triGroups.size(); i++) {
		const auto tris = triGroups[i];

		qvtxs[i].reserve(tris.size());

		for (uint32_t n = 0; n < tris.size(); n++) {
			const auto tri = tris[n];

			for (int t = 0; t < 3; t++) {
				uint32_t idx = tri->param.idx[t];
				const auto& v = vertices[idx];

				auto grid = ((aten::vec3)v.pos - bmin) * scale + real(0.5);

				uint32_t gx = (uint32_t)grid.x;
				uint32_t gy = (uint32_t)grid.y;
				uint32_t gz = (uint32_t)grid.z;

				uint64_t hash = gz * (gridX * gridY) + gy * gridX + gx;

				qvtxs[i].push_back(QVertex(v, idx, hash, gx, gy, gz));
			}
		}
	}

	// ObhɓĂ钸_̏ɂȂ悤Ƀ\[g.

	for (uint32_t i = 0; i < qvtxs.size(); i++)
	{
		std::sort(
			qvtxs[i].begin(), qvtxs[i].end(),
			[](const QVertex& q0, const QVertex& q1)
		{
			return q0.hash > q1.hash;
		});

		sortedIndices.reserve(triGroups[i].size());

		uint32_t num = (uint32_t)qvtxs[i].size();

		// CfbNX_ɂ킹ĕבւ.
		for (uint32_t n = 0; n < num; n++) {
			const auto& q = qvtxs[i][n];

			// X̃CfbNẌʒuɐVCfbNXl.
			sortedIndices[i][q.idx] = n;
		}
	}

	// ObhɓĂ钸_̕ϒlvZāAP̒_ɂĂ܂.
	// UV͕邪AFZJ_oEXɎĝŁA͋CɂȂ.

	for (uint32_t i = 0; i < qvtxs.size(); i++)
	{
		auto start = qvtxs[i].begin();

		while (start != qvtxs[i].end())
		{
			auto end = start;

			// ObhقȂ钸_ɂȂ܂ŒT.
			while (end != qvtxs[i].end() && start->hash == end->hash) {
				end++;
			}

			// TODO
			// όvZ.
			computeAverage(start, end);

			for (auto q = start; q != end; q++) {
				if (q == start) {
					dstVertices.push_back(q->v);
				}
				else {
					// قȂʒu̓_̏ꍇ.

					// O̓_Ɣr.
					auto prev = q - 1;

					auto v0 = q->v.pos;
					auto v1 = prev->v.pos;

					bool isEqual = (memcmp(&v0, &v1, sizeof(v0)) == 0);

					if (!isEqual) {
						dstVertices.push_back(q->v);
					}
				}

				// CfbNXXV.
				q->idx = (uint32_t)dstVertices.size() - 1;
			}

			// ̊JnʒuXV
			start = end;
		}
	}

	// LODꂽʂ̃CfbNXi[.

	dstIndices.resize(triGroups.size());

	for (uint32_t i = 0; i < triGroups.size(); i++) {
		const auto tris = triGroups[i];

		dstIndices[i].reserve(tris.size() * 3);

		for (uint32_t n = 0; n < tris.size(); n++) {
			const auto tri = tris[n];

			for (int t = 0; t < 3; t++) {
				uint32_t idx = tri->param.idx[t];

				auto sortedIdx = sortedIndices[i][idx];
				auto newIdx = qvtxs[i][sortedIdx].idx;

				dstIndices[i].push_back(newIdx);
			}
		}
	}
}
<|endoftext|>