/*
 * Copyright(C) 2000 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile$
 * \version $Revision: 165177 $
 * \date $Date:: 2017-10-26 13:15:08 +0300#$
 * \author $Author: frolov $
 *
 * \brief Функция регистрации ДСЧ.
 * Проект: интерфейс к датчикам случайных чисел (RNDM).
 * Функция регистрации ДСЧ.
 */

#include "rndm_prj.h" 
#include "reader.kit/reader.h"

/* для борьбы с динамическим распределением памяти не выделяем память под TRndmLevel,
 * а в указатель пишем TRndmLevel (или читаем из указателя TRndmLevel)
 * Это смущает статические анализаторы, но безопасно,
 * т.к. sizeof(TRndmLevel) <= sizeof(void*)
 */

/* Освобождение контекста считывателя. */
static DWORD rndm_free_item(TSupSysContext *list, TSupSysInfo *info);
/* Дублирование контекста считывателя. */
static DWORD rndm_dup_item(TSupSysContext *list, TSupSysInfo *info);
static DWORD rndm_alloc_item(TSupSysContext *list, TSupSysInfo *info);
static DWORD rndm_info_base_path(TSupSysContext *context, TSupSysInfo *info);
static DWORD rndm_info_version(TSupSysContext *context, TSupSysInfo *info);

static const TCHAR RANDOM_LIST_ROOT[] = _TEXT( "\\Config\\Random\\" );
static const TCHAR RANDOM_LIST_PARAM_LEVEL[] = _TEXT("\\Level");

static const TCHAR TC_RNDM_MSI_TITLE[] = _TEXT("rndm");
static const TCHAR TC_RNDM_ENTRY_POINT[] = _TEXT("_rndm_get_table");
static const TCHAR TC_RNDM_GROUP_POINT[] = _TEXT("_rndm_get_group_table");

static const TCHAR RNDM_BASE_PATH[] = _TEXT("\\CONFIG\\Random\\");

static const TSupSysInfoIDSBaseItem RNDM_IDS_BASE_ITEMS[] =
{
    {
	SUPSYS_IDS_BLOCK_WND,
	IDS_RNDM_WND_BASE,
	SUPSYS_IDS_WND_LAST
    },
    {
	READER_IDS_BLOCK,
	READER_IDS_BASE,
	READER_IDS_QUANT_V1
    }
};

/*!
* \ingroup rndm_internal
* \brief Таблица баз и границ строк в ресурсе по умолчанию.
*/
static const TSupSysInfoIDSBase RNDM_IDS_BASE =
{
    sizeof(RNDM_IDS_BASE_ITEMS) / sizeof(TSupSysInfoIDSBaseItem),
    RNDM_IDS_BASE_ITEMS
};


static DWORD rndm_info_ids(
    TSupSysContext *context,
    TSupSysInfo *info)
{
    UNUSED(context);

    SUPSYS_PRE_INFO(info, TSupSysInfoIDSBase);
    memcpy(info, &RNDM_IDS_BASE, sizeof(TSupSysInfoIDSBase));
    return ERROR_SUCCESS;
}




/*!
 * \brief Функция заполнения параметров регистрации
 * \param context [in] не используется
 * \param info [in,out] информация для регистрации
 * \return #ERROR_SUCCESS, #NTE_NO_MEMORY
 */
static DWORD rndm_alloc_item( TSupSysContext *context, TSupSysInfo *info )
{
    TSupSysListItemAlloc *inf = (TSupSysListItemAlloc*)info;

    UNUSED( context );
    SUPSYS_PRE_CCONTEXT( info, TSupSysListItemAlloc );
    /* см.комментарий в начале файла */
    memcpy(&inf->owner, &inf->add_info, sizeof(TRndmLevel)); //-V512
    return ERROR_SUCCESS;
}

static DWORD info_base_path(TSupSysEContext *context, TSupSysInfo *info,
    const TCHAR *path)
{
    TSupSysInfoText *inf = (TSupSysInfoText*)info;

    UNUSED(context);
    SUPSYS_PRE_INFO(info, TSupSysInfoText);
    if (inf->length && inf->text)
    {
	_tcsncpy(inf->text, path, inf->length);
	inf->text[inf->length] = 0;
    }
    inf->length = _tcslen(path);
    return ERROR_SUCCESS;
}


/*! 
 * \brief Функция сравнения регистрируемого элемента и проверяемого
 * \param context [in] не используется
 * \param info [in,out] информация для регистрации
 * \return результат проверки
 * \retval "< 0" регитсрируемый элемент меньше текущего
 * \retval ">= 0" регистрируемый элемент больше текущего
 */
static DWORD rndm_info_base_path(TSupSysContext *context, TSupSysInfo *info)
{
    return info_base_path(context, info, RNDM_BASE_PATH);
}

static DWORD rndm_compare_item( TSupSysContext *context, TSupSysInfo *info )
{
    TSupSysListItemCompare *inf = (TSupSysListItemCompare*)info;
    void *item1, *item2;
    TRndmLevel x1, x2;

    SUPSYS_PRE_INFO( info, TSupSysListItemCompare );
    UNUSED( context );

    /* см.комментарий в начале файла */
    item1 = supsys_owner_context(inf->item1);
    item2 = supsys_owner_context(inf->item2);

    memcpy(&x1, &item1, sizeof(TRndmLevel));
    memcpy(&x2, &item2, sizeof(TRndmLevel));
    inf->res = x1 - x2;

    return ERROR_SUCCESS;
}

static DWORD retTCHARConst(TSupSysContext *context, TSupSysInfo *info, SHORT reason)
{
    TSupSysInfoNickname *nick = (TSupSysInfoNickname *)info;

    UNUSED(context);

    if (info == NULL)
	return (DWORD)ERROR_INVALID_PARAMETER;

    switch (reason) {
    case 1:
	_tcscpy(nick->nickname, TC_RNDM_MSI_TITLE);
	break;
    case 2:
	_tcscpy(nick->nickname, TC_RNDM_ENTRY_POINT);
	break;
    case 3:
	_tcscpy(nick->nickname, TC_RNDM_GROUP_POINT);
	break;
    default:
	return (DWORD)ERROR_INVALID_PARAMETER;
    }
    return 0;
}


/*!
 * \brief Функция дублирования HANDLE
 * \param context [in] не используется
 * \param info [in,out] информация для регистрации
 * \return #ERROR_SUCCESS
 */
static DWORD rndm_dup_item( TSupSysContext *context, TSupSysInfo *info )
{
    TSupSysListItemDup *inf = (TSupSysListItemDup*)info;
    void *p;

    SUPSYS_PRE_INFO( info, TSupSysListItemDup );
    UNUSED( context );

    /* см.комментарий в начале файла */
    p = supsys_owner_context(inf->src);
    memcpy(&inf->dest_owner, &p, sizeof(TRndmLevel)); //-V512
    return ERROR_SUCCESS;
}

static DWORD rndm_free_item( TSupSysContext *context, TSupSysInfo *info )
{
    UNUSED(context);
    UNUSED(info);
    return ERROR_SUCCESS;
}

/*!
 * \brief Функция получения информации для регистрации из реестра
 * \param context [in] не используется
 * \param info [in,out] информация для регистрации
 * \return \link support_error Код ошибки\endlink
 */
static DWORD rndm_info_get_fun( TSupSysContext *context, TSupSysInfo *info )
{
    TCHAR *ptr;
    DWORD code;
    long l;
    TRndmLevel x;
    TSupSysListItemInfoGet *inf = (TSupSysListItemInfoGet*)info;

    SUPSYS_PRE_INFO( info, TSupSysListItemInfoGet );
    SUPSYS_PRE_STRING_PTRS( inf->path.text, inf->path.length );
    UNUSED( context );

    ptr = malloc( ( inf->path.length + _tcslen( RANDOM_LIST_PARAM_LEVEL ) + 1) 
	* sizeof(TCHAR) );
    if( ptr == NULL )
	return (DWORD)NTE_NO_MEMORY;
    _tcscpy( ptr, inf->path.text );
    _tcscat( ptr, RANDOM_LIST_PARAM_LEVEL );
    code = support_registry_get_long( ptr, &l );
    free( ptr );
    if( code == (DWORD)ERROR_FILE_NOT_FOUND )
    {
	l = -1;
	code = ERROR_SUCCESS;
    }
    if(code)
	return code;
    x = (TRndmLevel) l;
    memcpy(&inf->info.info, &x, sizeof(TRndmLevel)); //-V512
    inf->info.length = sizeof(TRndmLevel);
    return ERROR_SUCCESS;
}

/*!
 * \brief Функция уничтожения информации для регистрации
 * \param context [in] не используется
 * \param info [in] не используется
 */
static DWORD rndm_info_free_fun( TSupSysContext *context, TSupSysInfo *info )
{
    UNUSED(context);
    UNUSED(info);
    return ERROR_SUCCESS;
}

static DWORD rndm_msi_title(TSupSysContext *context, TSupSysInfo *info)
{
    return retTCHARConst(context, info, 1);
}

static DWORD rndm_prefix_name(TSupSysContext *context, TSupSysInfo *info)
{
    return retTCHARConst(context, info, 2);
}

static DWORD rndm_group_name(TSupSysContext *context, TSupSysInfo *info)
{
    return retTCHARConst(context, info, 3);
}

static const TSupSysFunctionTableItem RNDM_FUNS[] =
{
    { SUPSYS_FUN_IDS_BLOCK, rndm_info_ids },
    { SUPSYSL_FUN_BASE_PATH, rndm_info_base_path },
    { SUPSYSL_FUN_MSI_TITLE, rndm_msi_title },
    { SUPSYSL_FUN_PREFIX_NAME, rndm_prefix_name },
    { SUPSYSL_FUN_PREFIX_GROUP, rndm_group_name },

    { SUPSYSL_FUN_ITEM_ALLOC, rndm_alloc_item },
    { SUPSYSL_FUN_ITEM_FREE, rndm_free_item },
    { SUPSYSL_FUN_ITEM_DUP, rndm_dup_item }, 
    { SUPSYSL_FUN_ITEM_COMPARE, rndm_compare_item },
    { SUPSYSL_FUN_ITEM_INFO_GET, rndm_info_get_fun },
    { SUPSYSL_FUN_ITEM_INFO_FREE, rndm_info_free_fun },
    { SUPSYSL_FUN_ITEM_INFO_VERSION, rndm_info_version },
};

static const TSupSysFunctionTable RNDM_TABLE =
{
    sizeof( RNDM_FUNS ) / sizeof( TSupSysFunctionTableItem ),
    RNDM_FUNS
};
 
TRndmLevel rndm_level_get(const TSupSysEContext *context)
{
    /* см.комментарий в начале файла */
    TRndmLevel level;
    void *h = supsys_owner_context(context);
    memcpy(&level, &h, sizeof(TRndmLevel));
    return level;
}

DWORD rndm_level_set(const TSupSysEContext *context, TRndmLevel level)
{
    DWORD code;
    TCHAR *path;
    TSupSysNickname nickname;
    size_t length;
    static const TCHAR DEFAULT_CONNECT[] = _TEXT( "Default" );
    TCHAR *ptr;
    int def = 0;

    code = supsys_nickname( context, nickname );
    if( code )
	return code;
    code = supsys_connect_current( context, &length, NULL );
    if( code )
	return code;
    if( length == 0 )
    {
	length = _tcslen( DEFAULT_CONNECT );
	def = 1;
    }
    ptr = malloc( ( length + 1 ) * sizeof( TCHAR ) );
    if( !ptr )
	return (DWORD)NTE_NO_MEMORY;
    if( !def )
    {
	code = supsys_connect_current( context, &length, ptr );
	if( code )
	{
	    free( ptr );
	    return code;
	}
    }
    else
	_tcscpy( ptr, DEFAULT_CONNECT );
    path = malloc( ( _tcslen( RANDOM_LIST_ROOT ) + _tcslen( nickname ) 
	+ 1 + length
	+ _tcslen(RANDOM_LIST_PARAM_LEVEL) + 1 ) * sizeof(TCHAR) );
    if( path == NULL )
    {
	free( ptr );
	return (DWORD)NTE_NO_MEMORY;
    }
    _tcscpy( path, RANDOM_LIST_ROOT );
    _tcscat( path, nickname );
    _tcscat( path, _TEXT("\\") );
    _tcscat( path, ptr );
    free( ptr );
    _tcscat( path, RANDOM_LIST_PARAM_LEVEL );
    code = support_registry_put_long( path, level );
    free( path );
    if( code == (DWORD)NTE_NO_MEMORY )
	return code;
    if( code )
	return (DWORD)NTE_PROVIDER_DLL_FAIL;
    return ERROR_SUCCESS;
}

DWORD rndm_register_start(TSupSysEList **list)
{
    return supsys_register_start(list, &RNDM_TABLE);
}

static DWORD rndm_info_version( TSupSysContext *context, TSupSysInfo *info )
{  
    static const TSupSysInfoVersion _VERSION = {3,6,0,0};
    UNUSED( context );

    if(info == NULL)
	return (DWORD)ERROR_INVALID_PARAMETER;

    memcpy(info, &_VERSION, sizeof(_VERSION));
    return ERROR_SUCCESS;
}

#if defined _WIN32
DWORD rndm_set_hwnd(const TSupSysEContext *context, HWND hwnd) 
{
    DWORD code;
    code = supsys_call( context, RANDOM_FUN_HWND, &hwnd);
    if( code == (DWORD)ERROR_NOT_SUPPORTED )
	code = ERROR_SUCCESS;
    return code;
}
#endif	/* _WIN32 */
