<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "ccode.hpp"

#include <kdblogger.h>

namespace
{

/**
 * @brief Cast a character to an unsigned character.
 *
 * @param character This parameter specifies the character this function casts to an unsigned value.
 *
 * @return A unsigned character corresponding to the given argument
 */
inline constexpr unsigned char operator"" _uc (char character) noexcept
{
	return static_cast<unsigned char> (character);
}

/**
 * @brief This function maps hex characters to integer numbers.
 *
 * @pre The specified character has to be between
 *
 *      - `'0'`–`'9'`,
 *      - `'a'`-`'f'`, or
 *      - `'A'`-`'F'`
 *
 *     .
 *
 * @param character This argument specifies the (hexadecimal) character this function converts.
 *
 * @return An integer number between `0` and `15` if the precondition is valid or `0` otherwise
 */
inline int elektraHexcodeConvFromHex (char character)
{
	if (character >= '0' && character <= '9') return character - '0';
	if (character >= 'a' && character <= 'f') return character - 'a' + 10;
	if (character >= 'A' && character <= 'F') return character - 'A' + 10;

	return 0; /* Unknown escape char */
}

} // end namespace

using namespace ckdb;
extern "C" {

/**
 * @brief This function sets default values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with default values.
 */
void setDefaultConfig (CCodeData * const mapping)
{
	unsigned char pairs[][2] = { { '\b'_uc, 'b'_uc }, { '\t'_uc, 't'_uc }, { '\n'_uc, 'n'_uc },  { '\v'_uc, 'v'_uc },
				     { '\f'_uc, 'f'_uc }, { '\r'_uc, 'r'_uc }, { '\\'_uc, '\\'_uc }, { '\''_uc, '\''_uc },
				     { '\"'_uc, '"'_uc }, { '\0'_uc, '0'_uc } };

	for (size_t pair = 0; pair < sizeof (pairs) / sizeof (pairs[0]); pair++)
	{
		unsigned char character = pairs[pair][0];
		unsigned char replacement = pairs[pair][1];

		mapping->encode[character] = replacement;
		mapping->decode[replacement] = character;
	}
}

/**
 * @brief This function sets values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with the values specified in `config`.
 * @param config This key set stores the character mappings this function stores inside `mappings`.
 * @param root This key stores the root key for the character mapping stored in `config`.
 */
void readConfig (CCodeData * const mapping, KeySet * const config, Key const * const root)
{
	Key const * key = 0;
	while ((key = ksNext (config)) != 0)
	{
		/* Ignore keys that are not directly below the config root key or have an incorrect size */
		if (keyRel (root, key) != 1 || keyGetBaseNameSize (key) != 3 || keyGetValueSize (key) != 3) continue;

		int character = elektraHexcodeConvFromHex (keyBaseName (key)[1]);
		character += elektraHexcodeConvFromHex (keyBaseName (key)[0]) * 16;

		int replacement = elektraHexcodeConvFromHex (keyString (key)[1]);
		replacement += elektraHexcodeConvFromHex (keyString (key)[0]) * 16;

		/* Hexencode this character! */
		mapping->encode[character & 255] = replacement;
		mapping->decode[replacement & 255] = character;
	}
}

/**
 * @brief This function replaces escaped character in a key value with unescaped characters.
 *
 * The function stores the unescaped result value both in `mapping->buffer` and the given key.
 *
 * @pre The variable `mapping->buffer` needs to be as large as the key value’s size.
 *
 * @param key This key holds the value this function decodes.
 * @param mapping This variable stores the buffer and the character mapping this function uses to decode the value of the given key.
 */
void elektraCcodeDecode (Key * key, CCodeData * mapping)
{
	const char * value = static_cast<const char *> (keyValue (key));
	if (!value) return;

	size_t const SIZE = keyGetValueSize (key) - 1;
	size_t out = 0;
	for (size_t in = 0; in < SIZE; ++in)
	{
		unsigned char character = value[in];

		if (character == mapping->escape)
		{
			++in; /* Advance twice */
			character = value[in];

			mapping->buffer[out] = mapping->decode[character & 255];
		}
		else
		{
			mapping->buffer[out] = character;
		}
		++out; /* Only one char is written */
	}

	mapping->buffer[out] = 0; // null termination for keyString()

	keySetRaw (key, mapping->buffer, out + 1);
}

/**
 * @brief This function replaces unescaped character in a key value with escaped characters.
 *
 * The function stores the escaped result value both in `mapping->buffer` and the given key.
 *
 * @pre The variable `mapping->buffer` needs to be twice as large as the key value’s size.
 *
 * @param cur This key stores the value this function escapes.
 * @param mapping This variable stores the buffer and the character mapping this function uses to encode the value of the given key.
 */
void elektraCcodeEncode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (mapping->encode[character])
		{
			mapping->buffer[out + 1] = mapping->encode[character];
			// Escape char
			mapping->buffer[out] = mapping->escape;
			out += 2;
		}
		else
		{
			// just copy one character
			mapping->buffer[out] = val[in];
			// advance out cursor
			out++;
			// go to next char
		}
	}

	mapping->buffer[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buffer, out + 1);
}

// ====================
// = Plugin Interface =
// ====================

int elektraCcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = new CCodeData ();

	/* Store for later use...*/
	elektraPluginSetData (handle, mapping);

	KeySet * config = elektraPluginGetConfig (handle);

	Key * escape = ksLookupByName (config, "/escape", 0);
	mapping->escape = '\\';
	if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
	{
		int res;
		res = elektraHexcodeConvFromHex (keyString (escape)[1]);
		res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;

		mapping->escape = res & 255;
	}
	ELEKTRA_LOG_DEBUG ("Use “%c” as escape character", mapping->escape);

	Key * root = ksLookupByName (config, "/chars", 0);

	if (root)
	{
		readConfig (mapping, config, root);
	}
	else
	{
		setDefaultConfig (mapping);
	}

	return 0;
}

int elektraCcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));

	delete[](mapping->buffer);
	delete (mapping);

	return 0;
}

int elektraCcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/ccode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/ccode", KEY_VALUE, "ccode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/open", KEY_FUNC, elektraCcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/close", KEY_FUNC, elektraCcodeClose, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/get", KEY_FUNC, elektraCcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/set", KEY_FUNC, elektraCcodeSet, KEY_END),
#include "readme_ccode.c"
			       keyNew ("system/elektra/modules/ccode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buffer)
	{
		mapping->bufalloc = 1000;
		mapping->buffer = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > mapping->bufalloc)
		{
			mapping->bufalloc = valsize;
			mapping->buffer = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeDecode (cur, mapping);
	}

	return 1; /* success */
}

int elektraCcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
{
	/* set all keys */
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buffer)
	{
		mapping->bufalloc = 1000;
		mapping->buffer = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize * 2 > mapping->bufalloc)
		{
			mapping->bufalloc = valsize * 2;
			mapping->buffer = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeEncode (cur, mapping);
	}

	return 1; /* success */
}

Plugin * ELEKTRA_PLUGIN_EXPORT (ccode)
{
	// clang-format off
	return elektraPluginExport("ccode",
		ELEKTRA_PLUGIN_OPEN,	&elektraCcodeOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraCcodeClose,
		ELEKTRA_PLUGIN_GET,	&elektraCcodeGet,
		ELEKTRA_PLUGIN_SET,	&elektraCcodeSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<commit_msg>CCode: Only read size if we need it<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "ccode.hpp"

#include <kdblogger.h>

namespace
{

/**
 * @brief Cast a character to an unsigned character.
 *
 * @param character This parameter specifies the character this function casts to an unsigned value.
 *
 * @return A unsigned character corresponding to the given argument
 */
inline constexpr unsigned char operator"" _uc (char character) noexcept
{
	return static_cast<unsigned char> (character);
}

/**
 * @brief This function maps hex characters to integer numbers.
 *
 * @pre The specified character has to be between
 *
 *      - `'0'`–`'9'`,
 *      - `'a'`-`'f'`, or
 *      - `'A'`-`'F'`
 *
 *     .
 *
 * @param character This argument specifies the (hexadecimal) character this function converts.
 *
 * @return An integer number between `0` and `15` if the precondition is valid or `0` otherwise
 */
inline int elektraHexcodeConvFromHex (char character)
{
	if (character >= '0' && character <= '9') return character - '0';
	if (character >= 'a' && character <= 'f') return character - 'a' + 10;
	if (character >= 'A' && character <= 'F') return character - 'A' + 10;

	return 0; /* Unknown escape char */
}

} // end namespace

using namespace ckdb;
extern "C" {

/**
 * @brief This function sets default values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with default values.
 */
void setDefaultConfig (CCodeData * const mapping)
{
	unsigned char pairs[][2] = { { '\b'_uc, 'b'_uc }, { '\t'_uc, 't'_uc }, { '\n'_uc, 'n'_uc },  { '\v'_uc, 'v'_uc },
				     { '\f'_uc, 'f'_uc }, { '\r'_uc, 'r'_uc }, { '\\'_uc, '\\'_uc }, { '\''_uc, '\''_uc },
				     { '\"'_uc, '"'_uc }, { '\0'_uc, '0'_uc } };

	for (size_t pair = 0; pair < sizeof (pairs) / sizeof (pairs[0]); pair++)
	{
		unsigned char character = pairs[pair][0];
		unsigned char replacement = pairs[pair][1];

		mapping->encode[character] = replacement;
		mapping->decode[replacement] = character;
	}
}

/**
 * @brief This function sets values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with the values specified in `config`.
 * @param config This key set stores the character mappings this function stores inside `mappings`.
 * @param root This key stores the root key for the character mapping stored in `config`.
 */
void readConfig (CCodeData * const mapping, KeySet * const config, Key const * const root)
{
	Key const * key = 0;
	while ((key = ksNext (config)) != 0)
	{
		/* Ignore keys that are not directly below the config root key or have an incorrect size */
		if (keyRel (root, key) != 1 || keyGetBaseNameSize (key) != 3 || keyGetValueSize (key) != 3) continue;

		int character = elektraHexcodeConvFromHex (keyBaseName (key)[1]);
		character += elektraHexcodeConvFromHex (keyBaseName (key)[0]) * 16;

		int replacement = elektraHexcodeConvFromHex (keyString (key)[1]);
		replacement += elektraHexcodeConvFromHex (keyString (key)[0]) * 16;

		/* Hexencode this character! */
		mapping->encode[character & 255] = replacement;
		mapping->decode[replacement & 255] = character;
	}
}

/**
 * @brief This function replaces escaped character in a key value with unescaped characters.
 *
 * The function stores the unescaped result value both in `mapping->buffer` and the given key.
 *
 * @pre The variable `mapping->buffer` needs to be as large as the key value’s size.
 *
 * @param key This key holds the value this function decodes.
 * @param mapping This variable stores the buffer and the character mapping this function uses to decode the value of the given key.
 */
void elektraCcodeDecode (Key * key, CCodeData * mapping)
{
	const char * value = static_cast<const char *> (keyValue (key));
	if (!value) return;

	size_t const SIZE = keyGetValueSize (key) - 1;
	size_t out = 0;
	for (size_t in = 0; in < SIZE; ++in)
	{
		unsigned char character = value[in];

		if (character == mapping->escape)
		{
			++in; /* Advance twice */
			character = value[in];

			mapping->buffer[out] = mapping->decode[character & 255];
		}
		else
		{
			mapping->buffer[out] = character;
		}
		++out; /* Only one char is written */
	}

	mapping->buffer[out] = 0; // null termination for keyString()

	keySetRaw (key, mapping->buffer, out + 1);
}

/**
 * @brief This function replaces unescaped character in a key value with escaped characters.
 *
 * The function stores the escaped result value both in `mapping->buffer` and the given key.
 *
 * @pre The variable `mapping->buffer` needs to be twice as large as the key value’s size.
 *
 * @param cur This key stores the value this function escapes.
 * @param mapping This variable stores the buffer and the character mapping this function uses to encode the value of the given key.
 */
void elektraCcodeEncode (Key * cur, CCodeData * mapping)
{
	const char * val = static_cast<const char *> (keyValue (cur));
	if (!val) return;

	size_t valsize = keyGetValueSize (cur);
	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (mapping->encode[character])
		{
			mapping->buffer[out + 1] = mapping->encode[character];
			// Escape char
			mapping->buffer[out] = mapping->escape;
			out += 2;
		}
		else
		{
			// just copy one character
			mapping->buffer[out] = val[in];
			// advance out cursor
			out++;
			// go to next char
		}
	}

	mapping->buffer[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buffer, out + 1);
}

// ====================
// = Plugin Interface =
// ====================

int elektraCcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = new CCodeData ();

	/* Store for later use...*/
	elektraPluginSetData (handle, mapping);

	KeySet * config = elektraPluginGetConfig (handle);

	Key * escape = ksLookupByName (config, "/escape", 0);
	mapping->escape = '\\';
	if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
	{
		int res;
		res = elektraHexcodeConvFromHex (keyString (escape)[1]);
		res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;

		mapping->escape = res & 255;
	}
	ELEKTRA_LOG_DEBUG ("Use “%c” as escape character", mapping->escape);

	Key * root = ksLookupByName (config, "/chars", 0);

	if (root)
	{
		readConfig (mapping, config, root);
	}
	else
	{
		setDefaultConfig (mapping);
	}

	return 0;
}

int elektraCcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));

	delete[](mapping->buffer);
	delete (mapping);

	return 0;
}

int elektraCcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/ccode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/ccode", KEY_VALUE, "ccode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/open", KEY_FUNC, elektraCcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/close", KEY_FUNC, elektraCcodeClose, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/get", KEY_FUNC, elektraCcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/set", KEY_FUNC, elektraCcodeSet, KEY_END),
#include "readme_ccode.c"
			       keyNew ("system/elektra/modules/ccode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buffer)
	{
		mapping->bufalloc = 1000;
		mapping->buffer = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > mapping->bufalloc)
		{
			mapping->bufalloc = valsize;
			mapping->buffer = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeDecode (cur, mapping);
	}

	return 1; /* success */
}

int elektraCcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
{
	/* set all keys */
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buffer)
	{
		mapping->bufalloc = 1000;
		mapping->buffer = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize * 2 > mapping->bufalloc)
		{
			mapping->bufalloc = valsize * 2;
			mapping->buffer = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeEncode (cur, mapping);
	}

	return 1; /* success */
}

Plugin * ELEKTRA_PLUGIN_EXPORT (ccode)
{
	// clang-format off
	return elektraPluginExport("ccode",
		ELEKTRA_PLUGIN_OPEN,	&elektraCcodeOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraCcodeClose,
		ELEKTRA_PLUGIN_GET,	&elektraCcodeGet,
		ELEKTRA_PLUGIN_SET,	&elektraCcodeSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "ccode.hpp"

#include <kdblogger.h>

namespace
{

/**
 * @brief Cast a character to an unsigned character.
 *
 * @param character This parameter specifies the character this function casts to an unsigned value.
 *
 * @return A unsigned character corresponding to the given argument
 */
inline constexpr unsigned char operator"" _uc (char character) noexcept
{
	return static_cast<unsigned char> (character);
}

/**
 * @brief This function maps hex characters to integer numbers.
 *
 * @pre The specified character has to be between
 *
 *      - `'0'`–`'9'`,
 *      - `'a'`-`'f'`, or
 *      - `'A'`-`'F'`
 *
 *     .
 *
 * @param character This argument specifies the (hexadecimal) character this function converts.
 *
 * @return An integer number between `0` and `15` if the precondition is valid or `0` otherwise
 */
inline int elektraHexcodeConvFromHex (char character)
{
	if (character >= '0' && character <= '9') return character - '0';
	if (character >= 'a' && character <= 'f') return character - 'a' + 10;
	if (character >= 'A' && character <= 'F') return character - 'A' + 10;

	return 0; /* Unknown escape char */
}

} // end namespace

using namespace ckdb;
extern "C" {

/**
 * @brief This function sets default values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with default values.
 */
void setDefaultConfig (CCodeData * mapping)
{
	mapping->encode['\b'_uc] = 'b'_uc;
	mapping->encode['\t'_uc] = 't'_uc;
	mapping->encode['\n'_uc] = 'n'_uc;
	mapping->encode['\v'_uc] = 'v'_uc;
	mapping->encode['\f'_uc] = 'f'_uc;
	mapping->encode['\r'_uc] = 'r'_uc;
	mapping->encode['\\'_uc] = '\\'_uc;
	mapping->encode['\''_uc] = '\''_uc;
	mapping->encode['\"'_uc] = '"'_uc;
	mapping->encode['\0'_uc] = '0'_uc;

	mapping->decode['b'_uc] = '\b'_uc;
	mapping->decode['t'_uc] = '\t'_uc;
	mapping->decode['n'_uc] = '\n'_uc;
	mapping->decode['v'_uc] = '\v'_uc;
	mapping->decode['f'_uc] = '\f'_uc;
	mapping->decode['r'_uc] = '\r'_uc;
	mapping->decode['\\'_uc] = '\\'_uc;
	mapping->decode['\''_uc] = '\''_uc;
	mapping->decode['"'_uc] = '\"'_uc;
	mapping->decode['0'_uc] = '\0'_uc;
}

void readConfig (CCodeData * const mapping, KeySet * const config, Key const * const root)
{
	Key * cur = 0;
	while ((cur = ksNext (config)) != 0)
	{
		/* Ignore keys that are not directly below the config root key or have an incorrect size */
		if (keyRel (root, cur) != 1 || keyGetBaseNameSize (cur) != 3 || keyGetValueSize (cur) != 3) continue;

		int res;
		res = elektraHexcodeConvFromHex (keyBaseName (cur)[1]);
		res += elektraHexcodeConvFromHex (keyBaseName (cur)[0]) * 16;

		int val;
		val = elektraHexcodeConvFromHex (keyString (cur)[1]);
		val += elektraHexcodeConvFromHex (keyString (cur)[0]) * 16;

		/* Hexencode this character! */
		mapping->encode[res & 255] = val;
		mapping->decode[val & 255] = res;
	}
}

int elektraCcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = new CCodeData ();

	/* Store for later use...*/
	elektraPluginSetData (handle, mapping);

	KeySet * config = elektraPluginGetConfig (handle);

	Key * escape = ksLookupByName (config, "/escape", 0);
	mapping->escape = '\\';
	if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
	{
		int res;
		res = elektraHexcodeConvFromHex (keyString (escape)[1]);
		res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;

		mapping->escape = res & 255;
	}
	ELEKTRA_LOG_DEBUG ("Use “%c” as escape character", mapping->escape);

	Key * root = ksLookupByName (config, "/chars", 0);

	if (root)
	{
		readConfig (mapping, config, root);
	}
	else
	{
		setDefaultConfig (mapping);
	}

	return 0;
}

int elektraCcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));

	delete[](mapping->buf);
	delete (mapping);

	return 0;
}

/** Reads the value of the key and decodes all escaping
 * codes into the buffer.
 * @pre the buffer needs to be as large as value's size.
 * @param cur the key holding the value to decode
 * @param mapping the buffer to write to
 */
void elektraCcodeDecode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (character == mapping->escape)
		{
			++in; /* Advance twice */
			character = val[in];

			mapping->buf[out] = mapping->decode[character & 255];
		}
		else
		{
			mapping->buf[out] = character;
		}
		++out; /* Only one char is written */
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

int elektraCcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/ccode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/ccode", KEY_VALUE, "ccode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/open", KEY_FUNC, elektraCcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/close", KEY_FUNC, elektraCcodeClose, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/get", KEY_FUNC, elektraCcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/set", KEY_FUNC, elektraCcodeSet, KEY_END),
#include "readme_ccode.c"
			       keyNew ("system/elektra/modules/ccode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > mapping->bufalloc)
		{
			mapping->bufalloc = valsize;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeDecode (cur, mapping);
	}

	return 1; /* success */
}

/** Reads the value of the key and encodes it in
 * c-style in the buffer.
 *
 * @param cur the key which value is to encode
 * @param mapping the buffer
 * @pre the buffer needs to have twice as much space as the value's size
 */
void elektraCcodeEncode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (mapping->encode[character])
		{
			mapping->buf[out + 1] = mapping->encode[character];
			// Escape char
			mapping->buf[out] = mapping->escape;
			out += 2;
		}
		else
		{
			// just copy one character
			mapping->buf[out] = val[in];
			// advance out cursor
			out++;
			// go to next char
		}
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

int elektraCcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
{
	/* set all keys */
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize * 2 > mapping->bufalloc)
		{
			mapping->bufalloc = valsize * 2;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeEncode (cur, mapping);
	}

	return 1; /* success */
}

Plugin * ELEKTRA_PLUGIN_EXPORT (ccode)
{
	// clang-format off
	return elektraPluginExport("ccode",
		ELEKTRA_PLUGIN_OPEN,	&elektraCcodeOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraCcodeClose,
		ELEKTRA_PLUGIN_GET,	&elektraCcodeGet,
		ELEKTRA_PLUGIN_SET,	&elektraCcodeSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<commit_msg>CCode: Simplify function `setDefaultConfig`<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "ccode.hpp"

#include <kdblogger.h>

namespace
{

/**
 * @brief Cast a character to an unsigned character.
 *
 * @param character This parameter specifies the character this function casts to an unsigned value.
 *
 * @return A unsigned character corresponding to the given argument
 */
inline constexpr unsigned char operator"" _uc (char character) noexcept
{
	return static_cast<unsigned char> (character);
}

/**
 * @brief This function maps hex characters to integer numbers.
 *
 * @pre The specified character has to be between
 *
 *      - `'0'`–`'9'`,
 *      - `'a'`-`'f'`, or
 *      - `'A'`-`'F'`
 *
 *     .
 *
 * @param character This argument specifies the (hexadecimal) character this function converts.
 *
 * @return An integer number between `0` and `15` if the precondition is valid or `0` otherwise
 */
inline int elektraHexcodeConvFromHex (char character)
{
	if (character >= '0' && character <= '9') return character - '0';
	if (character >= 'a' && character <= 'f') return character - 'a' + 10;
	if (character >= 'A' && character <= 'F') return character - 'A' + 10;

	return 0; /* Unknown escape char */
}

} // end namespace

using namespace ckdb;
extern "C" {

/**
 * @brief This function sets default values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with default values.
 */
void setDefaultConfig (CCodeData * mapping)
{
	unsigned char pairs[][2] = { { '\b'_uc, 'b'_uc }, { '\t'_uc, 't'_uc }, { '\n'_uc, 'n'_uc },  { '\v'_uc, 'v'_uc },
				     { '\f'_uc, 'f'_uc }, { '\r'_uc, 'r'_uc }, { '\\'_uc, '\\'_uc }, { '\''_uc, '\''_uc },
				     { '\"'_uc, '"'_uc }, { '\0'_uc, '0'_uc } };

	for (size_t pair = 0; pair < sizeof (pairs) / sizeof (pairs[0]); pair++)
	{
		unsigned char character = pairs[pair][0];
		unsigned char replacement = pairs[pair][1];

		mapping->encode[character] = replacement;
		mapping->decode[replacement] = character;
	}
}

void readConfig (CCodeData * const mapping, KeySet * const config, Key const * const root)
{
	Key * cur = 0;
	while ((cur = ksNext (config)) != 0)
	{
		/* Ignore keys that are not directly below the config root key or have an incorrect size */
		if (keyRel (root, cur) != 1 || keyGetBaseNameSize (cur) != 3 || keyGetValueSize (cur) != 3) continue;

		int res;
		res = elektraHexcodeConvFromHex (keyBaseName (cur)[1]);
		res += elektraHexcodeConvFromHex (keyBaseName (cur)[0]) * 16;

		int val;
		val = elektraHexcodeConvFromHex (keyString (cur)[1]);
		val += elektraHexcodeConvFromHex (keyString (cur)[0]) * 16;

		/* Hexencode this character! */
		mapping->encode[res & 255] = val;
		mapping->decode[val & 255] = res;
	}
}

int elektraCcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = new CCodeData ();

	/* Store for later use...*/
	elektraPluginSetData (handle, mapping);

	KeySet * config = elektraPluginGetConfig (handle);

	Key * escape = ksLookupByName (config, "/escape", 0);
	mapping->escape = '\\';
	if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
	{
		int res;
		res = elektraHexcodeConvFromHex (keyString (escape)[1]);
		res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;

		mapping->escape = res & 255;
	}
	ELEKTRA_LOG_DEBUG ("Use “%c” as escape character", mapping->escape);

	Key * root = ksLookupByName (config, "/chars", 0);

	if (root)
	{
		readConfig (mapping, config, root);
	}
	else
	{
		setDefaultConfig (mapping);
	}

	return 0;
}

int elektraCcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));

	delete[](mapping->buf);
	delete (mapping);

	return 0;
}

/** Reads the value of the key and decodes all escaping
 * codes into the buffer.
 * @pre the buffer needs to be as large as value's size.
 * @param cur the key holding the value to decode
 * @param mapping the buffer to write to
 */
void elektraCcodeDecode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (character == mapping->escape)
		{
			++in; /* Advance twice */
			character = val[in];

			mapping->buf[out] = mapping->decode[character & 255];
		}
		else
		{
			mapping->buf[out] = character;
		}
		++out; /* Only one char is written */
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

int elektraCcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/ccode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/ccode", KEY_VALUE, "ccode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/open", KEY_FUNC, elektraCcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/close", KEY_FUNC, elektraCcodeClose, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/get", KEY_FUNC, elektraCcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/set", KEY_FUNC, elektraCcodeSet, KEY_END),
#include "readme_ccode.c"
			       keyNew ("system/elektra/modules/ccode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > mapping->bufalloc)
		{
			mapping->bufalloc = valsize;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeDecode (cur, mapping);
	}

	return 1; /* success */
}

/** Reads the value of the key and encodes it in
 * c-style in the buffer.
 *
 * @param cur the key which value is to encode
 * @param mapping the buffer
 * @pre the buffer needs to have twice as much space as the value's size
 */
void elektraCcodeEncode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (mapping->encode[character])
		{
			mapping->buf[out + 1] = mapping->encode[character];
			// Escape char
			mapping->buf[out] = mapping->escape;
			out += 2;
		}
		else
		{
			// just copy one character
			mapping->buf[out] = val[in];
			// advance out cursor
			out++;
			// go to next char
		}
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

int elektraCcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
{
	/* set all keys */
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize * 2 > mapping->bufalloc)
		{
			mapping->bufalloc = valsize * 2;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeEncode (cur, mapping);
	}

	return 1; /* success */
}

Plugin * ELEKTRA_PLUGIN_EXPORT (ccode)
{
	// clang-format off
	return elektraPluginExport("ccode",
		ELEKTRA_PLUGIN_OPEN,	&elektraCcodeOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraCcodeClose,
		ELEKTRA_PLUGIN_GET,	&elektraCcodeGet,
		ELEKTRA_PLUGIN_SET,	&elektraCcodeSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Ash Berlin, Rüdiger Sonderfeld

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 "flusspferd/class.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/security.hpp"
#include "flusspferd/modules.hpp"

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <cerrno>

using namespace flusspferd;

namespace {

int errno_getter() {
  return errno;
}

void errno_setter(int errno_) {
  errno = errno_;
}

std::string strerror_(int errno_) {
  return std::strerror(errno_);
}

FLUSSPFERD_LOADER(posix) {
  local_root_scope scope;

#ifdef HAVE_FORK
  // TODO: Need to work out how to make this play nice with the interactive repl
  create_native_function(posix, "fork", &::fork);
#endif

  create_native_function(posix, "sleep", &::sleep);

#ifdef HAVE_USLEEP
  create_native_function(posix, "usleep", usleep);
#endif

  // errno
  object errno_obj = create_object();
  function get_errno = create_native_function(errno_obj, "get", &errno_getter);
  function set_errno = create_native_function(errno_obj, "set", &errno_setter);
  property_attributes errno_attr(permanent_shared_property,
                                 get_errno, set_errno);
  posix.define_property("errno", errno, errno_attr);
  create_native_function(posix, "strerror", &strerror_);
  create_native_function(posix, "perror", &std::perror);
}

}

<commit_msg>posix: include header <cstdio>, as required<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Ash Berlin, Rüdiger Sonderfeld

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 "flusspferd/class.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/security.hpp"
#include "flusspferd/modules.hpp"

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <cerrno>
#include <cstdio>

using namespace flusspferd;

namespace {

int errno_getter() {
  return errno;
}

void errno_setter(int errno_) {
  errno = errno_;
}

std::string strerror_(int errno_) {
  return std::strerror(errno_);
}

FLUSSPFERD_LOADER(posix) {
  local_root_scope scope;

#ifdef HAVE_FORK
  // TODO: Need to work out how to make this play nice with the interactive repl
  create_native_function(posix, "fork", &::fork);
#endif

  create_native_function(posix, "sleep", &::sleep);

#ifdef HAVE_USLEEP
  create_native_function(posix, "usleep", usleep);
#endif

  // errno
  object errno_obj = create_object();
  function get_errno = create_native_function(errno_obj, "get", &errno_getter);
  function set_errno = create_native_function(errno_obj, "set", &errno_setter);
  property_attributes errno_attr(permanent_shared_property,
                                 get_errno, set_errno);
  posix.define_property("errno", errno, errno_attr);
  create_native_function(posix, "strerror", &strerror_);
  create_native_function(posix, "perror", &std::perror);
}

}

<|endoftext|>


<commit_before>
#include "EulerProblem.h"
#include "CLawCellMaterial.h"
#include "CLawFaceMaterial.h"
#include "CLawBoundaryMaterial.h"

using Eigen::Vector3d;

template<>
InputParameters validParams<EulerProblem>()
{
  InputParameters params = validParams<CFDProblem>();

  return params;
}

EulerProblem::EulerProblem(const std::string & name, InputParameters params) :
	CFDProblem(name, params)
{
}

void EulerProblem::computeCellFlux(RealGradient* flux, Real* source, Real* uh, RealGradient* duh)
{
	RealVectorValue inv_term[10], vis_term[10], source_term[10], artificial_term[10];
	inviscousTerm(inv_term, uh);
	viscousTerm(vis_term, uh, duh);
	sourceTerm(source, uh, duh);
	artificialViscous(artificial_term, uh, duh);
	for (int eq = 0; eq < _n_equations; ++eq)
		flux[eq] = inv_term[eq] - vis_term[eq] - artificial_term[eq];
}

void EulerProblem::computeFaceFlux(Real* flux, RealVectorValue* lift, Real* ul, Real* ur, RealGradient* dul, RealGradient* dur, Point& normal, Real penalty)
{
	RealVectorValue ifl[10], ifr[10], vfl[10], vfr[10];
	computeLift(lift, ul, ur, normal);

	viscousTerm(vfl, ul, dul);
	viscousTerm(vfr, ur, dur);

	fluxRiemann(flux, ul, ur, normal);

	for (int eq = 0; eq < _n_equations; ++eq)
	{
		flux[eq] -= 0.5*((vfl[eq]+vfr[eq])-penalty*lift[eq])*normal;
	}

}
void EulerProblem::artificialViscous(RealVectorValue* artificial_viscous, Real* uh, RealGradient* duh)
{
	RealVectorValue vel(uh[1], uh[2], uh[3]);
	vel /= uh[0];
	Real c = std::sqrt(temperature(uh))/_mach;
    Real indicator = uh[5] ;
//	Real viscosity = 1000;//10000*indicator;//* duh[0].size()/uh[0]*0.01;
	Real viscosity = 4*(vel.size() + c)*indicator;

	int component = 0;
	artificial_viscous[component] = viscosity*duh[component];

	component = 1;
	artificial_viscous[component] = viscosity*duh[component];

	component = 2;
	artificial_viscous[component] = viscosity*duh[component];

	component = 3;
	artificial_viscous[component] = viscosity*duh[component];

	component = 4;
	artificial_viscous[component] = viscosity*duh[component];
}

void EulerProblem::inviscousTerm(RealVectorValue* inviscous_term, Real* uh)
{
	Real rho, p, h;
	Real u, v, w;
	rho = uh[0];
	u = uh[1]/rho;
	v = uh[2]/rho;
	w = uh[3]/rho;
	p = pressure(uh);
	h = enthalpy(uh);

	int component = 0;

	component = 0;
	inviscous_term[component](0) = uh[1];	// rhou
	inviscous_term[component](1) = uh[2];	// rhov
	inviscous_term[component](2) = uh[3];	// rhow

	component = 1;
	inviscous_term[component](0) = uh[1] * u + p;
	inviscous_term[component](1) = uh[1] * v;
	inviscous_term[component](2) = uh[1] * w;

	component = 2;
	inviscous_term[component](0) = uh[2] * u;
	inviscous_term[component](1) = uh[2] * v + p;
	inviscous_term[component](2) = uh[2] * w;

	component = 3;
	inviscous_term[component](0) = uh[3] * u;
	inviscous_term[component](1) = uh[3] * v;
	inviscous_term[component](2) = uh[3] * w + p;

	component = 4;
	inviscous_term[component](0) = rho * h * u;
	inviscous_term[component](1) = rho * h * v;
	inviscous_term[component](2) = rho * h * w;
}

void EulerProblem::viscousTerm(RealVectorValue* viscous_term, Real* uh, RealGradient* duh)
{

	Real viscosity = 0.000;
	int component = 0;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 1;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 2;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 3;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 4;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];
}

void EulerProblem::fluxRiemann(Real* flux, Real* ul, Real* ur, Point &normal)
{
	RealVectorValue ifl[5], ifr[5], vfl[5], vfr[5];
	Real uh[5];

	inviscousTerm(ifl, ul);
	inviscousTerm(ifr, ur);

	for (int eq = 0; eq < _n_equations; ++eq)
		uh[eq] = (ul[eq]+ur[eq])/2;

	for (int eq = 0; eq < _n_equations; ++eq)
		flux[eq] = 0.5*(ifl[eq] + ifr[eq])*normal + maxEigenValue(uh, normal)*(ul[eq] - ur[eq]);
}

void EulerProblem::boundaryCondition(Real *ur, Real *ul, Point &normal, std::string bc_type)
{
	if(bc_type == "wall")
	{
		wall(ur, ul, normal);
		return;
	}
	if(bc_type == "far_field")
	{
		farField(ur, ul, normal);
		return;
	}
	if(bc_type == "symmetric")
	{
		symmetric(ur, ul, normal);
		return;
	}
	mooseError( bc_type << "未定义的边界条件类型");
}

void EulerProblem::wall(Real *ur,  Real *ul, Point &normal)
{
	RealVectorValue momentum(ul[1], ul[2], ul[3]);
    Real vn = momentum*normal;
    Real pre = pressure(ul);

    ur[0] = ul[0];
    ur[1] = ul[1] - 2.0 * vn * normal(0);
    ur[2] = ul[2] - 2.0 * vn * normal(1);
    ur[3] = ul[3] - 2.0 * vn * normal(2);
    ur[4] = pre/(_gamma-1) + 0.5*momentum.size_sq()/ur[0];
}

void EulerProblem::symmetric(Real *ur,  Real *ul, Point &normal)
{
	wall(ur, ul, normal);
}

void EulerProblem::farField(Real *ur,  Real *ul, Point &normal)
{
	Real rhoR, uR, vR, wR, pR;
	Real rhoL, uL, vL, wL, pL;
	Real cR, cL, cb;
	Real vnR, vnL, vnb;
	Real vel, s;
	Real Rp, Rm;

	Vector3d velocity = _attitude.earthFromWind()*Vector3d::UnitX();
	uR = velocity(0);
	vR = velocity(1);
	wR = velocity(2);
	rhoR = 1.0;

	pR = 1 / _gamma /_mach / _mach;
	cR = sqrt(fabs(_gamma * pR / rhoR));
	vnR = normal(0) * uR + normal(1) * vR + normal(2) * wR;

	rhoL = ul[0];
	uL = ul[1] / rhoL;
	vL = ul[2] / rhoL;
	wL = ul[3] / rhoL;
	vel = sqrt(uL * uL + vL * vL + wL * wL);
	pL = pressure(ul);
	cL = sqrt(fabs(_gamma * pL / rhoL));
	vnL =  normal(0) * uL + normal(1) * vL + normal(2) * wL;

	if (vel >= cL) {	//超声速
		if (vnL >= 0.0) //exit
		{
			ur[0] = ul[0];
			ur[1] = ul[1];
			ur[2] = ul[2];
			ur[3] = ul[3];
			ur[4] = ul[4];
		}
		else //inlet
		{
			ur[0] = rhoR;
			ur[1] = rhoR * uR;
			ur[2] = rhoR * vR;
			ur[3] = rhoR * wR;
			ur[4] = pR / (_gamma - 1) + 0.5 * rhoR * (uR * uR + vR * vR + wR * wR);
		}
	}
	else
	{ 	//  亚声速
		if (vnL >= 0.0)
		{			//exit
			s = pL / pow(rhoL, _gamma);
			Rp = vnL + 2 * cL / (_gamma - 1);
			Rm = vnR - 2 * cR / (_gamma - 1);
			vnb = (Rp + Rm) / 2.0;
			cb = (Rp - Rm) * (_gamma - 1) / 4.0;

			ur[0] = pow((cb * cb) / (s * _gamma), 1.0 / (_gamma - 1));
			ur[1] = ur[0] * (uL + normal(0) * (vnb - vnL));
			ur[2] = ur[0] * (vL + normal(1) * (vnb - vnL));
			ur[3] = ur[0] * (wL + normal(2) * (vnb - vnL));
			ur[4] = cb * cb * ur[0] / _gamma / (_gamma - 1) + 0.5 * (ur[1] * ur[1] + ur[2] * ur[2] + ur[3] * ur[3]) / ur[0];
		}
		else
		{
			s = pR / pow(rhoR, _gamma);
			Rp = -vnR + 2.0 * cR / (_gamma - 1);
			Rm = -vnL - 2.0 * cL / (_gamma - 1);
			vnb = -(Rp + Rm) / 2.0;
			cb = (Rp - Rm) * (_gamma - 1) / 4.0;

			ur[0] = pow((cb * cb) / (s * _gamma), 1.0 / (_gamma - 1));
			ur[1] = ur[0] * (uR + normal(0) * (vnb - vnR));
			ur[2] = ur[0] * (vR + normal(1) * (vnb - vnR));
			ur[3] = ur[0] * (wR + normal(2) * (vnb - vnR));
			ur[4] = cb * cb * ur[0] / _gamma / (_gamma - 1) + 0.5 * (ur[1] * ur[1] + ur[2] * ur[2] + ur[3] * ur[3]) / ur[0];
		}
	}
}

Real EulerProblem::physicalViscosity(Real* uh)
{
	return 0;
}

void EulerProblem::updateDependValue(DependValue& denpend_value, Real *uh)
{
	denpend_value.pressure = pressure(uh);
}
<commit_msg>测试BlastWave不成功<commit_after>
#include "EulerProblem.h"
#include "CLawCellMaterial.h"
#include "CLawFaceMaterial.h"
#include "CLawBoundaryMaterial.h"

using Eigen::Vector3d;

template<>
InputParameters validParams<EulerProblem>()
{
  InputParameters params = validParams<CFDProblem>();

  return params;
}

EulerProblem::EulerProblem(const std::string & name, InputParameters params) :
	CFDProblem(name, params)
{
}

void EulerProblem::computeCellFlux(RealGradient* flux, Real* source, Real* uh, RealGradient* duh)
{
	RealVectorValue inv_term[10], vis_term[10], source_term[10], artificial_term[10];
	inviscousTerm(inv_term, uh);
	viscousTerm(vis_term, uh, duh);
	sourceTerm(source, uh, duh);
	artificialViscous(artificial_term, uh, duh);
	for (int eq = 0; eq < _n_equations; ++eq)
		flux[eq] = inv_term[eq] - vis_term[eq] - artificial_term[eq];
}

void EulerProblem::computeFaceFlux(Real* flux, RealVectorValue* lift, Real* ul, Real* ur, RealGradient* dul, RealGradient* dur, Point& normal, Real penalty)
{
	RealVectorValue ifl[10], ifr[10], vfl[10], vfr[10];
	computeLift(lift, ul, ur, normal);

	viscousTerm(vfl, ul, dul);
	viscousTerm(vfr, ur, dur);

	fluxRiemann(flux, ul, ur, normal);

	for (int eq = 0; eq < _n_equations; ++eq)
	{
		flux[eq] -= 0.5*((vfl[eq]+vfr[eq])-penalty*lift[eq])*normal;
	}

}
void EulerProblem::artificialViscous(RealVectorValue* artificial_viscous, Real* uh, RealGradient* duh)
{
	RealVectorValue vel(uh[1], uh[2], uh[3]);
	vel /= uh[0];
	Real c = std::sqrt(temperature(uh))/_mach;
    Real indicator = uh[5] ;
//	Real viscosity = 1000;//10000*indicator;//* duh[0].size()/uh[0]*0.01;
	Real viscosity = 100;4*(vel.size() + c)*indicator;

	int component = 0;
	artificial_viscous[component] = viscosity*duh[component];

	component = 1;
	artificial_viscous[component] = viscosity*duh[component];

	component = 2;
	artificial_viscous[component] = viscosity*duh[component];

	component = 3;
	artificial_viscous[component] = viscosity*duh[component];

	component = 4;
	artificial_viscous[component] = viscosity*duh[component];
}

void EulerProblem::inviscousTerm(RealVectorValue* inviscous_term, Real* uh)
{
	Real rho, p, h;
	Real u, v, w;
	rho = uh[0];
	u = uh[1]/rho;
	v = uh[2]/rho;
	w = uh[3]/rho;
	p = pressure(uh);
	h = enthalpy(uh);

	int component = 0;

	component = 0;
	inviscous_term[component](0) = uh[1];	// rhou
	inviscous_term[component](1) = uh[2];	// rhov
	inviscous_term[component](2) = uh[3];	// rhow

	component = 1;
	inviscous_term[component](0) = uh[1] * u + p;
	inviscous_term[component](1) = uh[1] * v;
	inviscous_term[component](2) = uh[1] * w;

	component = 2;
	inviscous_term[component](0) = uh[2] * u;
	inviscous_term[component](1) = uh[2] * v + p;
	inviscous_term[component](2) = uh[2] * w;

	component = 3;
	inviscous_term[component](0) = uh[3] * u;
	inviscous_term[component](1) = uh[3] * v;
	inviscous_term[component](2) = uh[3] * w + p;

	component = 4;
	inviscous_term[component](0) = rho * h * u;
	inviscous_term[component](1) = rho * h * v;
	inviscous_term[component](2) = rho * h * w;
}

void EulerProblem::viscousTerm(RealVectorValue* viscous_term, Real* uh, RealGradient* duh)
{

	Real viscosity = 0.000;
	int component = 0;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 1;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 2;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 3;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];

	component = 4;
	viscous_term[component](0) = 0.;
	viscous_term[component](1) = 0.;
	viscous_term[component](2) = 0.;
	viscous_term[component] = viscosity*duh[component];
}

void EulerProblem::fluxRiemann(Real* flux, Real* ul, Real* ur, Point &normal)
{
	RealVectorValue ifl[5], ifr[5], vfl[5], vfr[5];
	Real uh[5];

	inviscousTerm(ifl, ul);
	inviscousTerm(ifr, ur);

	for (int eq = 0; eq < _n_equations; ++eq)
		uh[eq] = (ul[eq]+ur[eq])/2;

	for (int eq = 0; eq < _n_equations; ++eq)
		flux[eq] = 0.5*(ifl[eq] + ifr[eq])*normal + maxEigenValue(uh, normal)*(ul[eq] - ur[eq]);
}

void EulerProblem::boundaryCondition(Real *ur, Real *ul, Point &normal, std::string bc_type)
{
	if(bc_type == "wall")
	{
		wall(ur, ul, normal);
		return;
	}
	if(bc_type == "far_field")
	{
		farField(ur, ul, normal);
		return;
	}
	if(bc_type == "symmetric")
	{
		symmetric(ur, ul, normal);
		return;
	}
	mooseError( bc_type << "未定义的边界条件类型");
}

void EulerProblem::wall(Real *ur,  Real *ul, Point &normal)
{
	RealVectorValue momentum(ul[1], ul[2], ul[3]);
    Real vn = momentum*normal;
    Real pre = pressure(ul);

    ur[0] = ul[0];
    ur[1] = ul[1] - 2.0 * vn * normal(0);
    ur[2] = ul[2] - 2.0 * vn * normal(1);
    ur[3] = ul[3] - 2.0 * vn * normal(2);
    ur[4] = pre/(_gamma-1) + 0.5*momentum.size_sq()/ur[0];
}

void EulerProblem::symmetric(Real *ur,  Real *ul, Point &normal)
{
	wall(ur, ul, normal);
}

void EulerProblem::farField(Real *ur,  Real *ul, Point &normal)
{
	Real rhoR, uR, vR, wR, pR;
	Real rhoL, uL, vL, wL, pL;
	Real cR, cL, cb;
	Real vnR, vnL, vnb;
	Real vel, s;
	Real Rp, Rm;

	Vector3d velocity = _attitude.earthFromWind()*Vector3d::UnitX();
	uR = velocity(0);
	vR = velocity(1);
	wR = velocity(2);
	rhoR = 1.0;

	pR = 1 / _gamma /_mach / _mach;
	cR = sqrt(fabs(_gamma * pR / rhoR));
	vnR = normal(0) * uR + normal(1) * vR + normal(2) * wR;

	rhoL = ul[0];
	uL = ul[1] / rhoL;
	vL = ul[2] / rhoL;
	wL = ul[3] / rhoL;
	vel = sqrt(uL * uL + vL * vL + wL * wL);
	pL = pressure(ul);
	cL = sqrt(fabs(_gamma * pL / rhoL));
	vnL =  normal(0) * uL + normal(1) * vL + normal(2) * wL;

	if (vel >= cL) {	//超声速
		if (vnL >= 0.0) //exit
		{
			ur[0] = ul[0];
			ur[1] = ul[1];
			ur[2] = ul[2];
			ur[3] = ul[3];
			ur[4] = ul[4];
		}
		else //inlet
		{
			ur[0] = rhoR;
			ur[1] = rhoR * uR;
			ur[2] = rhoR * vR;
			ur[3] = rhoR * wR;
			ur[4] = pR / (_gamma - 1) + 0.5 * rhoR * (uR * uR + vR * vR + wR * wR);
		}
	}
	else
	{ 	//  亚声速
		if (vnL >= 0.0)
		{			//exit
			s = pL / pow(rhoL, _gamma);
			Rp = vnL + 2 * cL / (_gamma - 1);
			Rm = vnR - 2 * cR / (_gamma - 1);
			vnb = (Rp + Rm) / 2.0;
			cb = (Rp - Rm) * (_gamma - 1) / 4.0;

			ur[0] = pow((cb * cb) / (s * _gamma), 1.0 / (_gamma - 1));
			ur[1] = ur[0] * (uL + normal(0) * (vnb - vnL));
			ur[2] = ur[0] * (vL + normal(1) * (vnb - vnL));
			ur[3] = ur[0] * (wL + normal(2) * (vnb - vnL));
			ur[4] = cb * cb * ur[0] / _gamma / (_gamma - 1) + 0.5 * (ur[1] * ur[1] + ur[2] * ur[2] + ur[3] * ur[3]) / ur[0];
		}
		else
		{
			s = pR / pow(rhoR, _gamma);
			Rp = -vnR + 2.0 * cR / (_gamma - 1);
			Rm = -vnL - 2.0 * cL / (_gamma - 1);
			vnb = -(Rp + Rm) / 2.0;
			cb = (Rp - Rm) * (_gamma - 1) / 4.0;

			ur[0] = pow((cb * cb) / (s * _gamma), 1.0 / (_gamma - 1));
			ur[1] = ur[0] * (uR + normal(0) * (vnb - vnR));
			ur[2] = ur[0] * (vR + normal(1) * (vnb - vnR));
			ur[3] = ur[0] * (wR + normal(2) * (vnb - vnR));
			ur[4] = cb * cb * ur[0] / _gamma / (_gamma - 1) + 0.5 * (ur[1] * ur[1] + ur[2] * ur[2] + ur[3] * ur[3]) / ur[0];
		}
	}
}

Real EulerProblem::physicalViscosity(Real* uh)
{
	return 0;
}

void EulerProblem::updateDependValue(DependValue& denpend_value, Real *uh)
{
	denpend_value.pressure = pressure(uh);
}
<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (C) 2017, James R. Barlow (https://github.com/jbarlow83/)
 */

/*
 * Convert Python types <-> QPDFObjectHandle types
 */

#include <vector>
#include <map>
#include <cmath>

#include <qpdf/Constants.h>
#include <qpdf/Types.h>
#include <qpdf/DLL.h>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Buffer.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFWriter.hh>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include "pikepdf.h"

extern uint DECIMAL_PRECISION;

std::map<std::string, QPDFObjectHandle>
dict_builder(const py::dict dict)
{
    StackGuard sg(" dict_builder");
    std::map<std::string, QPDFObjectHandle> result;

    for (const auto& item: dict) {
        std::string key = item.first.cast<std::string>();

        auto value = objecthandle_encode(item.second);
        result[key] = value;
    }
    return result;
}

std::vector<QPDFObjectHandle>
array_builder(const py::iterable iter)
{
    StackGuard sg(" array_builder");
    std::vector<QPDFObjectHandle> result;
    int narg = 0;

    for (const auto& item: iter) {
        narg++;

        auto value = objecthandle_encode(item);
        result.push_back(value);
    }
    return result;
}

class DecimalPrecision {
public:
    DecimalPrecision(uint calc_precision) :
        decimal_context(py::module::import("decimal").attr("getcontext")()),
        saved_precision(decimal_context.attr("prec").cast<uint>())
    {
        decimal_context.attr("prec") = calc_precision;
    }
    ~DecimalPrecision() {
        decimal_context.attr("prec") = saved_precision;
    }
    DecimalPrecision(const DecimalPrecision& other) = delete;
    DecimalPrecision(DecimalPrecision&& other) = delete;
    DecimalPrecision& operator= (const DecimalPrecision& other) = delete;
    DecimalPrecision& operator= (DecimalPrecision&& other) = delete;
private:
    py::object decimal_context;
    uint saved_precision;
};

QPDFObjectHandle objecthandle_encode(const py::handle handle)
{
    if (handle.is_none())
        return QPDFObjectHandle::newNull();

    // Ensure that when we return QPDFObjectHandle/pikepdf.Object to the Py
    // environment, that we can recover it
    try {
        auto as_qobj = handle.cast<QPDFObjectHandle>();
        return as_qobj;
    } catch (const py::cast_error&) {}

    // Special-case booleans since pybind11 coerces nonzero integers to boolean
    if (py::isinstance<py::bool_>(handle)) {
        bool as_bool = handle.cast<bool>();
        return QPDFObjectHandle::newBool(as_bool);
    }

    auto decimal_module = py::module::import("decimal");
    auto Decimal = decimal_module.attr("Decimal");
    if (py::isinstance(handle, Decimal)) {
        DecimalPrecision dp(DECIMAL_PRECISION);
        auto rounded = py::reinterpret_steal<py::object>(PyNumber_Positive(handle.ptr()));
        if (! rounded.attr("is_finite")().cast<bool>())
            throw py::value_error("Can't convert NaN or Infinity to PDF real number");
        return QPDFObjectHandle::newReal(py::str(rounded));
    } else if (py::isinstance<py::int_>(handle)) {
        auto as_int = handle.cast<long long>();
        return QPDFObjectHandle::newInteger(as_int);
    } else if (py::isinstance<py::float_>(handle)) {
        auto as_double = handle.cast<double>();
        if (! isfinite(as_double))
            throw py::value_error("Can't convert NaN or Infinity to PDF real number");
        return QPDFObjectHandle::newReal(as_double);
    }

    py::object obj = py::reinterpret_borrow<py::object>(handle);

    if (py::isinstance<py::bytes>(obj)) {
        py::bytes py_bytes = obj;
        return QPDFObjectHandle::newString(static_cast<std::string>(py_bytes));
    } else if (py::isinstance<py::str>(obj)) {
        py::str py_str = obj;
        return QPDFObjectHandle::newUnicodeString(static_cast<std::string>(py_str));
    }

    if (py::hasattr(obj, "__iter__")) {
        //py::print(py::repr(obj));
        bool is_mapping = false; // PyMapping_Check is unreliable in Py3
        if (py::hasattr(obj, "keys"))
            is_mapping = true;

        bool is_sequence = PySequence_Check(obj.ptr());
        if (is_mapping) {
            return QPDFObjectHandle::newDictionary(dict_builder(obj));
        } else if (is_sequence) {
            return QPDFObjectHandle::newArray(array_builder(obj));
        }
    }

    throw py::cast_error(std::string("don't know how to encode value ") + std::string(py::repr(obj)));
}

py::object decimal_from_pdfobject(QPDFObjectHandle h)
{
    auto decimal_constructor = py::module::import("decimal").attr("Decimal");

    if (h.getTypeCode() == QPDFObject::object_type_e::ot_integer) {
        auto value = h.getIntValue();
        return decimal_constructor(py::cast(value));
    } else if (h.getTypeCode() == QPDFObject::object_type_e::ot_real) {
        auto value = h.getRealValue();
        return decimal_constructor(py::cast(value));
    } else if (h.getTypeCode() == QPDFObject::object_type_e::ot_boolean) {
        auto value = h.getBoolValue();
        return decimal_constructor(py::cast(value));
    }
    throw py::type_error("object has no Decimal() representation");
}
<commit_msg>Use std::isfinite() to fix compilation on GCC 5<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (C) 2017, James R. Barlow (https://github.com/jbarlow83/)
 */

/*
 * Convert Python types <-> QPDFObjectHandle types
 */

#include <vector>
#include <map>
#include <cmath>

#include <qpdf/Constants.h>
#include <qpdf/Types.h>
#include <qpdf/DLL.h>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/PointerHolder.hh>
#include <qpdf/Buffer.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFWriter.hh>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include "pikepdf.h"

extern uint DECIMAL_PRECISION;

std::map<std::string, QPDFObjectHandle>
dict_builder(const py::dict dict)
{
    StackGuard sg(" dict_builder");
    std::map<std::string, QPDFObjectHandle> result;

    for (const auto& item: dict) {
        std::string key = item.first.cast<std::string>();

        auto value = objecthandle_encode(item.second);
        result[key] = value;
    }
    return result;
}

std::vector<QPDFObjectHandle>
array_builder(const py::iterable iter)
{
    StackGuard sg(" array_builder");
    std::vector<QPDFObjectHandle> result;
    int narg = 0;

    for (const auto& item: iter) {
        narg++;

        auto value = objecthandle_encode(item);
        result.push_back(value);
    }
    return result;
}

class DecimalPrecision {
public:
    DecimalPrecision(uint calc_precision) :
        decimal_context(py::module::import("decimal").attr("getcontext")()),
        saved_precision(decimal_context.attr("prec").cast<uint>())
    {
        decimal_context.attr("prec") = calc_precision;
    }
    ~DecimalPrecision() {
        decimal_context.attr("prec") = saved_precision;
    }
    DecimalPrecision(const DecimalPrecision& other) = delete;
    DecimalPrecision(DecimalPrecision&& other) = delete;
    DecimalPrecision& operator= (const DecimalPrecision& other) = delete;
    DecimalPrecision& operator= (DecimalPrecision&& other) = delete;
private:
    py::object decimal_context;
    uint saved_precision;
};

QPDFObjectHandle objecthandle_encode(const py::handle handle)
{
    if (handle.is_none())
        return QPDFObjectHandle::newNull();

    // Ensure that when we return QPDFObjectHandle/pikepdf.Object to the Py
    // environment, that we can recover it
    try {
        auto as_qobj = handle.cast<QPDFObjectHandle>();
        return as_qobj;
    } catch (const py::cast_error&) {}

    // Special-case booleans since pybind11 coerces nonzero integers to boolean
    if (py::isinstance<py::bool_>(handle)) {
        bool as_bool = handle.cast<bool>();
        return QPDFObjectHandle::newBool(as_bool);
    }

    auto decimal_module = py::module::import("decimal");
    auto Decimal = decimal_module.attr("Decimal");
    if (py::isinstance(handle, Decimal)) {
        DecimalPrecision dp(DECIMAL_PRECISION);
        auto rounded = py::reinterpret_steal<py::object>(PyNumber_Positive(handle.ptr()));
        if (! rounded.attr("is_finite")().cast<bool>())
            throw py::value_error("Can't convert NaN or Infinity to PDF real number");
        return QPDFObjectHandle::newReal(py::str(rounded));
    } else if (py::isinstance<py::int_>(handle)) {
        auto as_int = handle.cast<long long>();
        return QPDFObjectHandle::newInteger(as_int);
    } else if (py::isinstance<py::float_>(handle)) {
        auto as_double = handle.cast<double>();
        if (! std::isfinite(as_double))
            throw py::value_error("Can't convert NaN or Infinity to PDF real number");
        return QPDFObjectHandle::newReal(as_double);
    }

    py::object obj = py::reinterpret_borrow<py::object>(handle);

    if (py::isinstance<py::bytes>(obj)) {
        py::bytes py_bytes = obj;
        return QPDFObjectHandle::newString(static_cast<std::string>(py_bytes));
    } else if (py::isinstance<py::str>(obj)) {
        py::str py_str = obj;
        return QPDFObjectHandle::newUnicodeString(static_cast<std::string>(py_str));
    }

    if (py::hasattr(obj, "__iter__")) {
        //py::print(py::repr(obj));
        bool is_mapping = false; // PyMapping_Check is unreliable in Py3
        if (py::hasattr(obj, "keys"))
            is_mapping = true;

        bool is_sequence = PySequence_Check(obj.ptr());
        if (is_mapping) {
            return QPDFObjectHandle::newDictionary(dict_builder(obj));
        } else if (is_sequence) {
            return QPDFObjectHandle::newArray(array_builder(obj));
        }
    }

    throw py::cast_error(std::string("don't know how to encode value ") + std::string(py::repr(obj)));
}

py::object decimal_from_pdfobject(QPDFObjectHandle h)
{
    auto decimal_constructor = py::module::import("decimal").attr("Decimal");

    if (h.getTypeCode() == QPDFObject::object_type_e::ot_integer) {
        auto value = h.getIntValue();
        return decimal_constructor(py::cast(value));
    } else if (h.getTypeCode() == QPDFObject::object_type_e::ot_real) {
        auto value = h.getRealValue();
        return decimal_constructor(py::cast(value));
    } else if (h.getTypeCode() == QPDFObject::object_type_e::ot_boolean) {
        auto value = h.getBoolValue();
        return decimal_constructor(py::cast(value));
    }
    throw py::type_error("object has no Decimal() representation");
}
<|endoftext|>


<commit_before>#include <framesgallery.hpp>
#include <QHBoxLayout>
#include <QFrame>
#include <QLabel>
#include <QMouseEvent>
#include <QMenu>

#include <animationframewidget.hpp>

FramesGallery::FramesGallery(QWidget *parent)
    :
      QWidget(parent),
      m_layout(new QHBoxLayout(this)),
      m_draggedFrame(nullptr),
      m_startDragIndex(-1),
      m_spacerIndex(-1),
      m_dragSpacer(new QSpacerItem(0, 0))
{
    setLayout(m_layout);
}

FramesGallery::~FramesGallery()
{
    delete m_dragSpacer;
}

void FramesGallery::reset()
{
    setSpritesheet();
    setFrames();
}

void FramesGallery::setFrames(const std::vector<AnimationFrame>& frames)
{
    clearGallery();

    int i = 0;
    for(const AnimationFrame& frame : frames)
    {
        m_frameWidgets.push_back(createFrameWidget(frame));
        m_layout->addWidget(m_frameWidgets.back());
        ++i;
    }

    if(!m_frameWidgets.empty())
    {
        m_frameWidgets.front()->setStyleSheet("background: #ADD8E6;");
        emit frameSelected(frames.front());
    }
}

void FramesGallery::updateGallery()
{

}

void FramesGallery::addFrame(const AnimationFrame& frame)
{
    auto&& frameWidget = createFrameWidget(frame);
    m_frameWidgets.emplace_back(frameWidget);
    m_layout->addWidget(m_frameWidgets.back());
}

void FramesGallery::updateFrame(int at, const AnimationFrame &updatedFrame)
{
    if(at >= 0 && static_cast<unsigned>(at) < m_frameWidgets.size())
    {
        m_frameWidgets[at]->deleteLater();
        auto&& frameWidget = createFrameWidget(updatedFrame);
        m_layout->replaceWidget(m_frameWidgets[at], frameWidget);
        m_frameWidgets[at] = frameWidget;
    }
}

AnimationFrameWidget *FramesGallery::createFrameWidget(const AnimationFrame &frame)
{
    AnimationFrameWidget* frameWidget = new AnimationFrameWidget(frame.getName(),
                                                                 m_spritesheet.copy(frame.getRect()),
                                                                 this);

    connect(frameWidget, &AnimationFrameWidget::framePressed, [this, frame, frameWidget]
    {
        //Reset all widgets stylesheet
        std::for_each(m_frameWidgets.begin(), m_frameWidgets.end(), [](QWidget* w) { w->setStyleSheet(""); });
        frameWidget->setStyleSheet("background: #ADD8E6;");
        emit frameSelected(frame);
        //Handle dragging
        m_draggedFrame = frameWidget;
        //Get start drag position
        m_startDragPos = mapFromGlobal(QCursor::pos());
        //Get index of frame in layout so we can replace it with spacer item
        m_startDragIndex = m_spacerIndex = m_layout->indexOf(m_draggedFrame);
        //Remove widget from layout
        m_layout->removeWidget(m_draggedFrame);
        //Make spacer width and height same as dragged frame
        m_dragSpacer->changeSize(m_draggedFrame->size().width(), m_draggedFrame->size().height());
        //And insert spacer at position
        m_layout->insertSpacerItem(m_spacerIndex, m_dragSpacer);
    });

    connect(frameWidget, &AnimationFrameWidget::frameReleased, [this, frameWidget]
    {
        if(m_draggedFrame == frameWidget)
        {
            //Insert dragged frame at spacer position
            m_layout->removeItem(m_dragSpacer);
            m_layout->insertWidget(m_spacerIndex, m_draggedFrame);
            if(m_spacerIndex != m_startDragIndex)
                emit frameMoved(m_startDragIndex, m_spacerIndex);
            m_startDragIndex = m_spacerIndex = -1;
            m_draggedFrame = nullptr;
        }
    });

    connect(frameWidget, &AnimationFrameWidget::frameRightClicked, [this, frame, frameWidget]
    {
        std::for_each(m_frameWidgets.begin(), m_frameWidgets.end(), [](QWidget* w) { w->setStyleSheet(""); });
        frameWidget->setStyleSheet("background: #ADD8E6;");
        emit frameSelected(frame);

        QMenu contextMenu(tr("Frame context"), this);
        QAction newFrameAction(tr("New frame"), this);
        connect(&newFrameAction, &QAction::triggered, [this](bool){ emit newFrameRequested(); });
        QAction removeFrameAction(tr("Remove frame"), this);
        //TODO
        QAction editFrameAction(tr("Edit frame"), this);
        connect(&editFrameAction, &QAction::triggered, [this, frameWidget](bool){ emit editFrameRequested(m_layout->indexOf(frameWidget)); });

        contextMenu.addAction(&newFrameAction);
        contextMenu.addAction(&removeFrameAction);
        contextMenu.addSeparator();
        contextMenu.addAction(&editFrameAction);

        contextMenu.exec(QCursor::pos());
    });

    connect(frameWidget, &AnimationFrameWidget::frameDoubleClicked, [this, frameWidget]
    {
        emit frameDoubleClicked(m_layout->indexOf(frameWidget));
    });

    return frameWidget;
}

void FramesGallery::setSpritesheet(const QPixmap &spritesheet)
{
    m_spritesheet = spritesheet;
}

void FramesGallery::clearGallery()
{
    if(m_frameWidgets.size() > 0)
    {
        std::for_each(m_frameWidgets.begin(), m_frameWidgets.end(), [](AnimationFrameWidget* widget) { widget->deleteLater(); });
        m_frameWidgets.clear();
        m_layout->removeItem(m_dragSpacer);
    }
}

void FramesGallery::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::MouseButton::RightButton)
    {
        QMenu contextMenu(tr("New frame context"), this);
        QAction newFrameAction(tr("New frame"), this);
        connect(&newFrameAction, &QAction::triggered, [this](bool){ emit newFrameRequested(); });
        contextMenu.addAction(&newFrameAction);
        contextMenu.exec(QCursor::pos());
    }
}

void FramesGallery::mouseMoveEvent(QMouseEvent *event)
{
    if(m_draggedFrame)
    {
        QPoint subPos = event->pos() - m_startDragPos;
        if(m_draggedFrame->pos().x() + subPos.x() >= pos().x() - (m_draggedFrame->size().width() / 2) &&
           m_draggedFrame->pos().x() + m_draggedFrame->size().width() + subPos.x() < pos().x() + size().width() + (m_draggedFrame->size().width() / 2))
            m_draggedFrame->move(m_draggedFrame->pos().x() + subPos.x(), m_draggedFrame->pos().y());
        m_startDragPos = event->pos();

        //TODO I believe this can look better
        if(m_layout->count() > 1)
        {
            //When spacer is in middle of frames but not at the beggining and end
            if(m_spacerIndex > 0 && m_spacerIndex < m_layout->count() - 1)
            {
                const auto widgetAfterSpacer = m_layout->itemAt(m_spacerIndex + 1)->widget();
                //Handle after spacer
                if(m_draggedFrame->pos().x() > widgetAfterSpacer->pos().x())
                {
                    m_layout->removeItem(m_dragSpacer);
                    m_layout->insertSpacerItem(++m_spacerIndex, m_dragSpacer);
                }
                const auto widgetBeforeSpacer = m_layout->itemAt(m_spacerIndex - 1)->widget();
                //Handle before spacer
                if(m_draggedFrame->pos().x() < widgetBeforeSpacer->pos().x())
                {
                    m_layout->removeItem(m_dragSpacer);
                    m_layout->insertSpacerItem(--m_spacerIndex, m_dragSpacer);
                }
            }
            else if(m_spacerIndex == 0) // Spacer at the beginning
            {
                 const auto widgetAfterSpacer = m_layout->itemAt(m_spacerIndex + 1)->widget();
                 if(m_draggedFrame->pos().x() > widgetAfterSpacer->pos().x())
                 {
                     m_layout->removeItem(m_dragSpacer);
                     m_layout->insertSpacerItem(++m_spacerIndex, m_dragSpacer);
                 }
            }
            else if(m_spacerIndex == m_layout->count() - 1) // Spacer at the end
            {
                const auto widgetBeforeSpacer = m_layout->itemAt(m_spacerIndex - 1)->widget();
                if(m_draggedFrame->pos().x() < widgetBeforeSpacer->pos().x())
                {
                    m_layout->removeItem(m_dragSpacer);
                    m_layout->insertSpacerItem(--m_spacerIndex, m_dragSpacer);
                }
            }
        }
    }
}
<commit_msg>Deleted updateGallery method which caused build to fail<commit_after>#include <framesgallery.hpp>
#include <QHBoxLayout>
#include <QFrame>
#include <QLabel>
#include <QMouseEvent>
#include <QMenu>

#include <animationframewidget.hpp>

FramesGallery::FramesGallery(QWidget *parent)
    :
      QWidget(parent),
      m_layout(new QHBoxLayout(this)),
      m_draggedFrame(nullptr),
      m_startDragIndex(-1),
      m_spacerIndex(-1),
      m_dragSpacer(new QSpacerItem(0, 0))
{
    setLayout(m_layout);
}

FramesGallery::~FramesGallery()
{
    delete m_dragSpacer;
}

void FramesGallery::reset()
{
    setSpritesheet();
    setFrames();
}

void FramesGallery::setFrames(const std::vector<AnimationFrame>& frames)
{
    clearGallery();

    int i = 0;
    for(const AnimationFrame& frame : frames)
    {
        m_frameWidgets.push_back(createFrameWidget(frame));
        m_layout->addWidget(m_frameWidgets.back());
        ++i;
    }

    if(!m_frameWidgets.empty())
    {
        m_frameWidgets.front()->setStyleSheet("background: #ADD8E6;");
        emit frameSelected(frames.front());
    }
}

void FramesGallery::addFrame(const AnimationFrame& frame)
{
    auto&& frameWidget = createFrameWidget(frame);
    m_frameWidgets.emplace_back(frameWidget);
    m_layout->addWidget(m_frameWidgets.back());
}

void FramesGallery::updateFrame(int at, const AnimationFrame &updatedFrame)
{
    if(at >= 0 && static_cast<unsigned>(at) < m_frameWidgets.size())
    {
        m_frameWidgets[at]->deleteLater();
        auto&& frameWidget = createFrameWidget(updatedFrame);
        m_layout->replaceWidget(m_frameWidgets[at], frameWidget);
        m_frameWidgets[at] = frameWidget;
    }
}

AnimationFrameWidget *FramesGallery::createFrameWidget(const AnimationFrame &frame)
{
    AnimationFrameWidget* frameWidget = new AnimationFrameWidget(frame.getName(),
                                                                 m_spritesheet.copy(frame.getRect()),
                                                                 this);

    connect(frameWidget, &AnimationFrameWidget::framePressed, [this, frame, frameWidget]
    {
        //Reset all widgets stylesheet
        std::for_each(m_frameWidgets.begin(), m_frameWidgets.end(), [](QWidget* w) { w->setStyleSheet(""); });
        frameWidget->setStyleSheet("background: #ADD8E6;");
        emit frameSelected(frame);
        //Handle dragging
        m_draggedFrame = frameWidget;
        //Get start drag position
        m_startDragPos = mapFromGlobal(QCursor::pos());
        //Get index of frame in layout so we can replace it with spacer item
        m_startDragIndex = m_spacerIndex = m_layout->indexOf(m_draggedFrame);
        //Remove widget from layout
        m_layout->removeWidget(m_draggedFrame);
        //Make spacer width and height same as dragged frame
        m_dragSpacer->changeSize(m_draggedFrame->size().width(), m_draggedFrame->size().height());
        //And insert spacer at position
        m_layout->insertSpacerItem(m_spacerIndex, m_dragSpacer);
    });

    connect(frameWidget, &AnimationFrameWidget::frameReleased, [this, frameWidget]
    {
        if(m_draggedFrame == frameWidget)
        {
            //Insert dragged frame at spacer position
            m_layout->removeItem(m_dragSpacer);
            m_layout->insertWidget(m_spacerIndex, m_draggedFrame);
            if(m_spacerIndex != m_startDragIndex)
                emit frameMoved(m_startDragIndex, m_spacerIndex);
            m_startDragIndex = m_spacerIndex = -1;
            m_draggedFrame = nullptr;
        }
    });

    connect(frameWidget, &AnimationFrameWidget::frameRightClicked, [this, frame, frameWidget]
    {
        std::for_each(m_frameWidgets.begin(), m_frameWidgets.end(), [](QWidget* w) { w->setStyleSheet(""); });
        frameWidget->setStyleSheet("background: #ADD8E6;");
        emit frameSelected(frame);

        QMenu contextMenu(tr("Frame context"), this);
        QAction newFrameAction(tr("New frame"), this);
        connect(&newFrameAction, &QAction::triggered, [this](bool){ emit newFrameRequested(); });
        QAction removeFrameAction(tr("Remove frame"), this);
        //TODO
        QAction editFrameAction(tr("Edit frame"), this);
        connect(&editFrameAction, &QAction::triggered, [this, frameWidget](bool){ emit editFrameRequested(m_layout->indexOf(frameWidget)); });

        contextMenu.addAction(&newFrameAction);
        contextMenu.addAction(&removeFrameAction);
        contextMenu.addSeparator();
        contextMenu.addAction(&editFrameAction);

        contextMenu.exec(QCursor::pos());
    });

    connect(frameWidget, &AnimationFrameWidget::frameDoubleClicked, [this, frameWidget]
    {
        emit frameDoubleClicked(m_layout->indexOf(frameWidget));
    });

    return frameWidget;
}

void FramesGallery::setSpritesheet(const QPixmap &spritesheet)
{
    m_spritesheet = spritesheet;
}

void FramesGallery::clearGallery()
{
    if(m_frameWidgets.size() > 0)
    {
        std::for_each(m_frameWidgets.begin(), m_frameWidgets.end(), [](AnimationFrameWidget* widget) { widget->deleteLater(); });
        m_frameWidgets.clear();
        m_layout->removeItem(m_dragSpacer);
    }
}

void FramesGallery::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::MouseButton::RightButton)
    {
        QMenu contextMenu(tr("New frame context"), this);
        QAction newFrameAction(tr("New frame"), this);
        connect(&newFrameAction, &QAction::triggered, [this](bool){ emit newFrameRequested(); });
        contextMenu.addAction(&newFrameAction);
        contextMenu.exec(QCursor::pos());
    }
}

void FramesGallery::mouseMoveEvent(QMouseEvent *event)
{
    if(m_draggedFrame)
    {
        QPoint subPos = event->pos() - m_startDragPos;
        if(m_draggedFrame->pos().x() + subPos.x() >= pos().x() - (m_draggedFrame->size().width() / 2) &&
           m_draggedFrame->pos().x() + m_draggedFrame->size().width() + subPos.x() < pos().x() + size().width() + (m_draggedFrame->size().width() / 2))
            m_draggedFrame->move(m_draggedFrame->pos().x() + subPos.x(), m_draggedFrame->pos().y());
        m_startDragPos = event->pos();

        //TODO I believe this can look better
        if(m_layout->count() > 1)
        {
            //When spacer is in middle of frames but not at the beggining and end
            if(m_spacerIndex > 0 && m_spacerIndex < m_layout->count() - 1)
            {
                const auto widgetAfterSpacer = m_layout->itemAt(m_spacerIndex + 1)->widget();
                //Handle after spacer
                if(m_draggedFrame->pos().x() > widgetAfterSpacer->pos().x())
                {
                    m_layout->removeItem(m_dragSpacer);
                    m_layout->insertSpacerItem(++m_spacerIndex, m_dragSpacer);
                }
                const auto widgetBeforeSpacer = m_layout->itemAt(m_spacerIndex - 1)->widget();
                //Handle before spacer
                if(m_draggedFrame->pos().x() < widgetBeforeSpacer->pos().x())
                {
                    m_layout->removeItem(m_dragSpacer);
                    m_layout->insertSpacerItem(--m_spacerIndex, m_dragSpacer);
                }
            }
            else if(m_spacerIndex == 0) // Spacer at the beginning
            {
                 const auto widgetAfterSpacer = m_layout->itemAt(m_spacerIndex + 1)->widget();
                 if(m_draggedFrame->pos().x() > widgetAfterSpacer->pos().x())
                 {
                     m_layout->removeItem(m_dragSpacer);
                     m_layout->insertSpacerItem(++m_spacerIndex, m_dragSpacer);
                 }
            }
            else if(m_spacerIndex == m_layout->count() - 1) // Spacer at the end
            {
                const auto widgetBeforeSpacer = m_layout->itemAt(m_spacerIndex - 1)->widget();
                if(m_draggedFrame->pos().x() < widgetBeforeSpacer->pos().x())
                {
                    m_layout->removeItem(m_dragSpacer);
                    m_layout->insertSpacerItem(--m_spacerIndex, m_dragSpacer);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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.
 */

#include <android/log.h>
#include <dlfcn.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

namespace art {

class SignalAction {
 public:
  SignalAction() : claimed_(false) {
  }

  // Claim the signal and keep the action specified.
  void Claim(const struct sigaction& action) {
    action_ = action;
    claimed_ = true;
  }

  // Unclaim the signal and restore the old action.
  void Unclaim(int signal) {
    claimed_ = false;
    sigaction(signal, &action_, NULL);        // Restore old action.
  }

  // Get the action associated with this signal.
  const struct sigaction& GetAction() const {
    return action_;
  }

  // Is the signal claimed?
  bool IsClaimed() const {
    return claimed_;
  }

  // Change the recorded action to that specified.
  void SetAction(const struct sigaction& action) {
    action_ = action;
  }

 private:
  struct sigaction action_;     // Action to be performed.
  bool claimed_;                // Whether signal is claimed or not.
};

// User's signal handlers
static SignalAction user_sigactions[_NSIG];

static void log(const char* format, ...) {
  char buf[256];
  va_list ap;
  va_start(ap, format);
  vsnprintf(buf, sizeof(buf), format, ap);
  __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
  va_end(ap);
}

static void CheckSignalValid(int signal) {
  if (signal <= 0 || signal >= _NSIG) {
    log("Invalid signal %d", signal);
    abort();
  }
}

// Claim a signal chain for a particular signal.
void ClaimSignalChain(int signal, struct sigaction* oldaction) {
  CheckSignalValid(signal);
  user_sigactions[signal].Claim(*oldaction);
}

void UnclaimSignalChain(int signal) {
  CheckSignalValid(signal);

  user_sigactions[signal].Unclaim(signal);
}

// Invoke the user's signal handler.
void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
  // Check the arguments.
  CheckSignalValid(sig);

  // The signal must have been claimed in order to get here.  Check it.
  if (!user_sigactions[sig].IsClaimed()) {
    abort();
  }

  const struct sigaction& action = user_sigactions[sig].GetAction();

  // Only deliver the signal if the signal was not masked out.
  if (sigismember(&action.sa_mask, sig)) {
     return;
  }
  if ((action.sa_flags & SA_SIGINFO) == 0) {
    if (action.sa_handler != NULL) {
      action.sa_handler(sig);
    }
  } else {
    if (action.sa_sigaction != NULL) {
      action.sa_sigaction(sig, info, context);
    }
  }
}

extern "C" {
// These functions are C linkage since they replace the functions in libc.

int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
  // If this signal has been claimed as a signal chain, record the user's
  // action but don't pass it on to the kernel.
  // Note that we check that the signal number is in range here.  An out of range signal
  // number should behave exactly as the libc sigaction.
  if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
    if (old_action != NULL) {
      *old_action = user_sigactions[signal].GetAction();
    }
    if (new_action != NULL) {
      user_sigactions[signal].SetAction(*new_action);
    }
    return 0;
  }

  // Will only get here if the signal chain has not been claimed.  We want
  // to pass the sigaction on to the kernel via the real sigaction in libc.

  void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
  if (linked_sigaction_sym == nullptr) {
    log("Unable to find next sigaction in signal chain");
    abort();
  }

  typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
  SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
  return linked_sigaction(signal, new_action, old_action);
}

int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
  const sigset_t* new_set_ptr = bionic_new_set;
  sigset_t tmpset;
  if (bionic_new_set != NULL) {
    tmpset = *bionic_new_set;

    if (how == SIG_BLOCK) {
      // Don't allow claimed signals in the mask.  If a signal chain has been claimed
      // we can't allow the user to block that signal.
      for (int i = 0 ; i < _NSIG; ++i) {
        if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
            sigdelset(&tmpset, i);
        }
      }
    }
    new_set_ptr = &tmpset;
  }

  void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
  if (linked_sigprocmask_sym == nullptr) {
    log("Unable to find next sigprocmask in signal chain");
    abort();
  }

  typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
  SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
  return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
}
}   // extern "C"
}   // namespace art

<commit_msg>am b796d1bf: Merge "Remove incorrect check for sa_mask in signal chaining"<commit_after>/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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.
 */

#include <android/log.h>
#include <dlfcn.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

namespace art {

class SignalAction {
 public:
  SignalAction() : claimed_(false) {
  }

  // Claim the signal and keep the action specified.
  void Claim(const struct sigaction& action) {
    action_ = action;
    claimed_ = true;
  }

  // Unclaim the signal and restore the old action.
  void Unclaim(int signal) {
    claimed_ = false;
    sigaction(signal, &action_, NULL);        // Restore old action.
  }

  // Get the action associated with this signal.
  const struct sigaction& GetAction() const {
    return action_;
  }

  // Is the signal claimed?
  bool IsClaimed() const {
    return claimed_;
  }

  // Change the recorded action to that specified.
  void SetAction(const struct sigaction& action) {
    action_ = action;
  }

 private:
  struct sigaction action_;     // Action to be performed.
  bool claimed_;                // Whether signal is claimed or not.
};

// User's signal handlers
static SignalAction user_sigactions[_NSIG];

static void log(const char* format, ...) {
  char buf[256];
  va_list ap;
  va_start(ap, format);
  vsnprintf(buf, sizeof(buf), format, ap);
  __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
  va_end(ap);
}

static void CheckSignalValid(int signal) {
  if (signal <= 0 || signal >= _NSIG) {
    log("Invalid signal %d", signal);
    abort();
  }
}

// Claim a signal chain for a particular signal.
void ClaimSignalChain(int signal, struct sigaction* oldaction) {
  CheckSignalValid(signal);
  user_sigactions[signal].Claim(*oldaction);
}

void UnclaimSignalChain(int signal) {
  CheckSignalValid(signal);

  user_sigactions[signal].Unclaim(signal);
}

// Invoke the user's signal handler.
void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
  // Check the arguments.
  CheckSignalValid(sig);

  // The signal must have been claimed in order to get here.  Check it.
  if (!user_sigactions[sig].IsClaimed()) {
    abort();
  }

  const struct sigaction& action = user_sigactions[sig].GetAction();
  if ((action.sa_flags & SA_SIGINFO) == 0) {
    if (action.sa_handler != NULL) {
      action.sa_handler(sig);
    }
  } else {
    if (action.sa_sigaction != NULL) {
      action.sa_sigaction(sig, info, context);
    }
  }
}

extern "C" {
// These functions are C linkage since they replace the functions in libc.

int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
  // If this signal has been claimed as a signal chain, record the user's
  // action but don't pass it on to the kernel.
  // Note that we check that the signal number is in range here.  An out of range signal
  // number should behave exactly as the libc sigaction.
  if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
    if (old_action != NULL) {
      *old_action = user_sigactions[signal].GetAction();
    }
    if (new_action != NULL) {
      user_sigactions[signal].SetAction(*new_action);
    }
    return 0;
  }

  // Will only get here if the signal chain has not been claimed.  We want
  // to pass the sigaction on to the kernel via the real sigaction in libc.

  void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
  if (linked_sigaction_sym == nullptr) {
    log("Unable to find next sigaction in signal chain");
    abort();
  }

  typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
  SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
  return linked_sigaction(signal, new_action, old_action);
}

int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
  const sigset_t* new_set_ptr = bionic_new_set;
  sigset_t tmpset;
  if (bionic_new_set != NULL) {
    tmpset = *bionic_new_set;

    if (how == SIG_BLOCK) {
      // Don't allow claimed signals in the mask.  If a signal chain has been claimed
      // we can't allow the user to block that signal.
      for (int i = 0 ; i < _NSIG; ++i) {
        if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
            sigdelset(&tmpset, i);
        }
      }
    }
    new_set_ptr = &tmpset;
  }

  void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
  if (linked_sigprocmask_sym == nullptr) {
    log("Unable to find next sigprocmask in signal chain");
    abort();
  }

  typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
  SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
  return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
}
}   // extern "C"
}   // namespace art

<|endoftext|>