Exemple #1
0
tu_string	tu_string::utf8_substring ( int start, int end ) const
{
	assert ( start <= end );

	if ( start == end )
	{
		// Special case, always return empty string.
		return tu_string();
	}

	const char	*p = get_buffer();
	int	index = 0;
	const char	*start_pointer = p;
	const char	*end_pointer = p;

	for ( ;; )
	{
		if ( index == start )
		{
			start_pointer = p;
		}

		uint32	c = utf8::decode_next_unicode_character ( &p );
		index++;

		if ( index == end )
		{
			end_pointer = p;
			break;
		}

		if ( c == 0 )
		{
			if ( index < end )
			{
				assert ( 0 );
				end_pointer = p;
			}

			break;
		}
	}

	if ( end_pointer < start_pointer )
	{
		end_pointer = start_pointer;
	}

	return tu_string ( start_pointer, int ( end_pointer - start_pointer ) );
}
// setText
// set text on edit
void CMenuFxObj::setText( const char *lpString )
{
	if (m_character && m_character->is(gameswf::AS_EDIT_TEXT))
	{
		gameswf::edit_text_character* edit_text = (gameswf::edit_text_character*)m_character;
		edit_text->set_text_value( tu_string(lpString) );
	}
}
Exemple #3
0
http_status http_server::http_request_state::parse_request_line(const char* reqline)
// Parses the first line of an HTTP request.  Fills in fields in m_req
// appropriately.  Returns HTTP result code, 400+ if we detected an
// error, HTTP_OK if the parse is OK.
{
	VLOG("parse_request_line(), sock = %x: %s\n", m_req.m_sock, reqline);

	// Method.
	const char* first_space = strchr(reqline, ' ');
	if (first_space == NULL || first_space == reqline)
	{
		// No method.
		return HTTP_BAD_REQUEST;
	}
	m_req.m_method = tu_string(reqline, first_space - reqline);

	// URI.
	const char* second_space = strchr(first_space + 1, ' ');
	if (second_space == NULL || second_space == first_space + 1)
	{
		// No URI.
		return HTTP_BAD_REQUEST;
	}
	m_req.m_uri = tu_string(first_space + 1, second_space - first_space - 1);

	// HTTP version.
	const char* version = second_space + 1;
	if (strncmp(version, "HTTP/1.0", 8) == 0)
	{
		m_req.m_http_version_x256 = 0x0100;
	}
	else if (strncmp(version, "HTTP/1.1", 8) == 0)
	{
		m_req.m_http_version_x256 = 0x0101;
	}
	else
	{
		return HTTP_HTTP_VERSION_NOT_SUPPORTED;
	}

	return HTTP_OK;  // OK so far.
}
// setText
// set tex with unicode
void CMenuFxObj::setText( const wchar_t *lpString )
{
	if (m_character && m_character->is(gameswf::AS_EDIT_TEXT))
	{
		gameswf::edit_text_character* edit_text = (gameswf::edit_text_character*)m_character;

		char stringc[1024];
		uiString::convertUnicodeToUTF8(lpString, stringc );
		edit_text->set_text_value( tu_string(stringc) );
	}
}
Exemple #5
0
void http_server::http_request_state::parse_query_string(const char* query)
// Parses a URL-encoded query string.  Puts decoded param/value pairs
// into m_req.m_params.
{
	while (query) {
		const char* equals = strchr(query, '=');
		tu_string param;
		tu_string value;
		if (equals) {
			param = tu_string(query, equals - query);
			
			// Find the end of the value and update the query.
			query = strchr(query, '&');
			if (query) {
				value = tu_string(equals + 1, query - (equals + 1));
				query++;  // Skip the '&'
			} else {
				value = equals + 1;
			}
		} else {
			const char* next_query = strchr(query, '&');
			if (next_query) {
				param = tu_string(query, next_query - query);
				next_query++;  // Skip the '&'
			} else {
				param = query;
			}
			
			query = next_query;
		}

		unescape_url_component(&param);
		unescape_url_component(&value);

		if (param.length()) {
			m_req.add_param(param, value);
		}
	}
}
Exemple #6
0
tu_string trim_whitespace(const char* buf)
// Return the arg with whitespace at either end trimmed off.
{
	const char* c = buf;
	while (is_whitespace(c[0]))
	{
		c++;
	}
	int end = strlen(c);
	while (end > 0 && is_whitespace(c[end - 1]))
	{
		end--;
	}
	
	return tu_string(c, end);
}
Exemple #7
0
http_status http_server::http_request_state::process_header()
// Call this after finishing parsing the header.  Sets the following
// parse state.  Returns an HTTP status code.
{
	assert(m_request_state == PARSE_HEADER);
	assert(m_req.m_body.length() == 0);

	// Set up path/file vars.
	const char* pathend = strchr(m_req.m_uri.c_str(), '?');
	const char* query = NULL;
	if (pathend) {
		query = pathend + 1;
	} else {
		pathend = m_req.m_uri.c_str() + m_req.m_uri.length();
	}
	m_req.m_path = tu_string(m_req.m_uri.c_str(), pathend - m_req.m_uri.c_str());
	unescape_url_component(&m_req.m_path);
	
	const char* filestart = strrchr(m_req.m_path.c_str(), '/');
	if (filestart)
	{
		m_req.m_file = (filestart + 1);
		unescape_url_component(&m_req.m_file);
	}

	// Parse params in the request string.
	parse_query_string(query);

	m_content_length = -1;
	tu_string content_length_str;
	if (m_req.m_header.get("content-length", &content_length_str))
	{
		m_content_length = atol(content_length_str.c_str());
		if (m_content_length > MAX_CONTENT_LENGTH_ACCEPTED)
		{
			m_request_state = PARSE_DONE;
			return HTTP_REQUEST_ENTITY_TOO_LARGE;
		}
	}
	
	tu_string transfer_encoding;
	if (m_req.m_header.get("transfer-encoding", &transfer_encoding))
	{
		if (transfer_encoding.to_tu_stringi() == "chunked")
		{
			// We're required to ignore the content-length
			// header.
			m_content_length = -1;
			m_request_state = PARSE_BODY_CHUNKED_CHUNK;
			return parse_body();
		}
		else if (transfer_encoding.to_tu_stringi() == "identity")
		{
			// This is OK; basically a no-op.
		}
		else
		{
			// A transfer encoding we don't know how to handle.
			// Reject it.
			m_request_state = PARSE_DONE;
			return HTTP_NOT_IMPLEMENTED;
		}
	}

	// If there's a body section, then we need to read it & parse it.
	if (m_content_length >= 0)
	{
		m_request_state = PARSE_BODY_IDENTITY;
		return parse_body();
	}
	else
	{
		m_request_state = PARSE_DONE;
	}
	
	return HTTP_OK;
}
Exemple #8
0
http_status http_server::http_request_state::parse_header_line(const char* hline)
// Parse a header line.  Call this multiple lines, once with each
// header line, to build up m_req.
//
// Sets m_request_state to PARSE_BODY if hline is the last header line.
//
// Returns an error code >= 400 on error; < 400 on success.
{
	assert(m_request_state == PARSE_HEADER);

	if (hline[0] == '\r' && hline[1] == '\n')
	{
		// End of the header.
		
		// Finish the previous key.
		if (m_parse_key.length())
		{
			m_req.m_header.set(m_parse_key, m_parse_value);
		}

		return process_header();
	}

	if (is_linear_whitepace(hline[0]))
	{
		// Looks like a continuation.
		if (m_parse_key.length())
		{
			m_parse_value += " ";
			m_parse_value += trim_whitespace(hline);
			return HTTP_OK;
		}
		else
		{
			// Non-continuation line starts with whitespace.
			return HTTP_BAD_REQUEST;
		}
	}
	
	// Finish any previous key.
	if (m_parse_key.length())
	{
		m_req.m_header.set(m_parse_key, m_parse_value);
		m_parse_key = "";
		m_parse_value = "";
	}

	const char* first_colon = strchr(hline, ':');
	if (first_colon == NULL || first_colon == hline)
	{
		return HTTP_BAD_REQUEST;
	}

	// Start a key/value pair.
	m_parse_key = tu_string(hline, first_colon - hline).utf8_to_lower();

	// Fill in any value-so-far from an earlier occurrence of this header.
	assert(m_parse_value.length() == 0);
	m_req.m_header.get(m_parse_key, &m_parse_value);
	if (m_parse_value.length())
	{
		m_parse_value += ",";
	}
	
	m_parse_value += trim_whitespace(first_colon + 1);

	return HTTP_OK;
}
int	main()
{
#if 1
	printf("sizeof(tu_string) == %d\n", sizeof(tu_string));

	swf_array<tu_string>	storage;
	storage.resize(2);

	tu_string&	a = storage[0];
	tu_string&	b = storage[1];
	a = "test1";
	
	printf("&a = 0x%X, &b = 0x%X\n", int(&a), int(&b));

	printf("%s\n", a.c_str());

	assert(a == "test1");
	assert(a.length() == 5);

	a += "2";
	assert(a == "test12");

	a += "this is some more text";
	assert(a.length() == 28);

	assert(a[2] == 's');
	assert(a[3] == 't');
	assert(a[4] == '1');
	assert(a[5] == '2');
	assert(a[7] == 'h');
	assert(a[28] == 0);

	assert(b.length() == 0);
	assert(b[0] == 0);
	assert(b.c_str()[0] == 0);

	tu_string c = a + b;

	assert(c.length() == a.length());

	c.resize(2);
	assert(c == "te");
	assert(c == tu_string("te"));

	assert(tu_string("fourscore and sevent") == "fourscore and sevent");

	b = "#sacrificial lamb";

	// Test growing & shrinking.
	a = "";
	for (int i = 0; i < 1000; i++)
	{
		assert(a.length() == i);

		if (i == 8)
		{
			assert(a == "01234567");
		}
		else if (i == 27)
		{
			assert(a == "012345678901234567890123456");
		}

		a.resize(a.length() + 1);
		a[a.length() - 1] = '0' + (i % 10);
	}

	{for (int i = 999; i >= 0; i--)
	{
		a.resize(a.length() - 1);
		assert(a.length() == i);

		if (i == 8)
		{
			assert(a == "01234567");
		}
		else if (i == 27)
		{
			assert(a == "012345678901234567890123456");
		}
	}}

	// Test larger shrinking across heap/local boundary.
	a = "this is a string longer than 16 characters";
	a = "short";

	// Test larger expand across heap/local boundary.
	a = "another longer string...";

	assert(b == "#sacrificial lamb");

	// Test erase()
	a = "abcdef";
	a.erase(3, 1);
	assert(a == "abcef");
	a = "abcdefghijklmnopqrst";
	a.erase(12, 6);
	assert(a == "abcdefghijklst");

	// Test insert()
	a = "abcdef";
	a.insert(3, 'z');
	assert(a == "abczdef");
	a = "abcdefghijklmn";
	a.insert(12, 'y');
	a.insert(13, 'z');
	assert(a == "abcdefghijklyzmn");

	// Test operator+=(tu_string)
	a = "abcdef";
	b = "ghijklmnopqrst";
	a += b;
	assert(a == "abcdefghijklmnopqrst");

	// Test operator+(const char*)
	a = "abcdef";
	b = "ghi";
	assert(a + b == "abcdefghi");

	// Test operator<(const char*)
	a = "abc";
	assert(a < "def");
	assert(a < "abd");
	assert(!(a < "aab"));
	assert(!(a < "aa"));
	assert(!(a < "aabz"));
	assert(a < "abcd");

	// Test operator<(const tu_string&)
	a = "abc";
	assert(a < tu_string("def"));
	assert(a < tu_string("abd"));
	assert(!(a < tu_string("aab")));
	assert(!(a < tu_string("aa")));
	assert(!(a < tu_string("aabz")));
	assert(a < tu_string("abcd"));

	// Test that we can store strings with embedded \0's.
	a = "abc";
	a += '\0';
	assert(a.length() == 4);
	a += "def";
	assert(a.length() == 7);
	assert(a[4] == 'd');
	assert(a[5] == 'e');
	assert(a[6] == 'f');
	assert(a[7] == 0);

	// Test that we can upsize strings with embedded \0's
	a = "abc";
	a += '\0';
	a += "def";
	b = a;
	assert(a == b);
	assert(b.length() == 7);
	a = a + b;
	assert(a.length() == 14);
	assert(a == (b + b));
	assert(a > b);
	a = a + b;
	assert(a.size() == 21);
	assert(a == (b + b + b));
	assert(a > b);

	// Test that we can downsize strings with embedded \0's
	a = "abc";
	a += '\0';
	a += "def";
	assert(a.length() == 7);
	b = a + a + a;
	assert(b.length() == 21);
	b.resize(14);
	assert(b.length() == 14);
	assert(b == (a + a));
	b.erase(3, 1);
	assert(b.size() == 13);
	assert(b == tu_string("abcdef") + a);

	// Test strings that are nothing but \0's.
	a = "";
	b = "";
	for (int i = 0; i < 100; i++) {
		a += '\0';
		assert(a.length() == i + 1);
		assert(a > b);
		b += '\0';
		assert(b.length() == i + 1);
		assert(a == b);
		assert((a + b).length() == 2 * (i + 1));
	}

	test_hash();
	test_stringi();
	test_stringi_hash();

	test_unicode();

	// TODO: unit tests for swf_array<>, string_hash<>
#endif

	test_hash_speed();

	printf("OK\n");

	return 0;
}
	bool UIFontFileSelector ( const char *font_name, tu_string &file_name, bool is_bold, bool is_italic )
	{
		if ( 1 )
		{
			file_name = tu_string ( "data/fonts/OFLArialUnicode.otf" );
			return true;
		}

		else
		{
			//Vitaly: I'm not sure that this code works on all versions of Windows
			tu_stringi fontname = font_name;

			if ( is_bold )
			{
				fontname += " Bold";
			}

			if ( is_italic )
			{
				fontname +=  " Italic";
			}

			fontname += " (TrueType)";
			HKEY hKey;
			// try WinNT
			DWORD retCode = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
			                               "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
			                               0,
			                               KEY_ALL_ACCESS,
			                               &hKey );

			if ( retCode != ERROR_SUCCESS )
			{
				// try Windows
				retCode = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
				                         "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
				                         0,
				                         KEY_ALL_ACCESS,
				                         &hKey );

				if ( retCode != ERROR_SUCCESS )
				{
					return false;
				}
			}

			// Get the value of the 'windir' environment variable.
			tu_string windir ( getenv ( "WINDIR" ) );
			// Get value count.
			DWORD    cValues;              // number of values for key
			retCode = RegQueryInfoKey (
			              hKey,	// key handle
			              NULL,	// buffer for class name
			              NULL,	// size of class string
			              NULL,	// reserved
			              NULL,	// number of subkeys
			              NULL,	// longest subkey size
			              NULL,	// longest class string
			              &cValues,	// number of values for this key
			              NULL,	// longest value name
			              NULL,	// longest value data
			              NULL,	// security descriptor
			              NULL );	// last write time
			// Enumerate the key values.
			BYTE szValueData[MAX_PATH];
			TCHAR  achValue[MAX_PATH];

			for ( DWORD i = 0, retCode = ERROR_SUCCESS; i < cValues; i++ )
			{
				DWORD cchValue = MAX_PATH;
				DWORD dwValueDataSize = sizeof ( szValueData ) - 1;
				achValue[0] = '\0';
				retCode = RegEnumValueA ( hKey, i,
				                          achValue,
				                          &cchValue,
				                          NULL,
				                          NULL,
				                          szValueData,
				                          &dwValueDataSize );

				if ( retCode == ERROR_SUCCESS )
				{
					if ( ( fontname == ( char * ) achValue ) || ( ( strstr ( achValue, font_name ) != NULL ) && !is_italic && !is_bold ) )
					{
						file_name = windir + tu_string ( "\\Fonts\\" ) + ( char * ) szValueData;
						RegCloseKey ( hKey );
						return true;
					}
				}
			}

			RegCloseKey ( hKey );
		}

		return false;
	}
Exemple #11
0
net_socket* http_connection::connect(const char* c_url, int port)
{
	char* url = strdup(c_url);

	// get host name from url
	// find the first '/'
	int i, n;
	for (i = 0, n = (int) strlen(url); url[i] != '/' && i < n; i++);
	if (i == n)
	{
		// '/' is not found
		fprintf(stderr, "invalid url '%s'\n", url);
		free(url);
		return NULL;
	}

	tu_string uri = url + i;
	url[i] = 0;
	tu_string host = url;
	free(url);
	url = NULL;

	if (net_init() == false)
	{
		return NULL;
	}

	m_iface = new net_interface_tcp();

	// Open a socket to receive connections on.
	m_ns = m_iface->connect(host.c_str(), port);

	if (m_ns == NULL)
	{
		fprintf(stderr, "Couldn't open net interface\n");
		delete m_iface;
		m_iface = NULL;
		return NULL;
	}

	// connect to HTTP server
	if (get_proxy_port() > 0)
	{
		char buf[512];
		snprintf(buf, 512, "CONNECT %s:%d HTTP/1.0\r\n", host.c_str(), port);
		m_ns->write_string(buf, HTTP_TIMEOUT);
		m_ns->write_string("User-Agent:gameswf\r\n", HTTP_TIMEOUT);
		m_ns->write_string("Connection:Keep-Alive\r\n", HTTP_TIMEOUT);
		m_ns->write_string("\r\n", HTTP_TIMEOUT);
		if (read_response() == false)
		{
			fprintf(stderr, "Couldn't connect to '%s' through proxy '%s'\n", 
				host.c_str(), get_proxy());
			delete m_ns;
			m_ns = NULL;
			return NULL;
		}
	}

	// We use HTTP/1.0 because we do not wont get chunked encoding data
	m_ns->write_string(tu_string("GET ") + uri + tu_string(" HTTP/1.0\r\n"), HTTP_TIMEOUT);
	m_ns->write_string(tu_string("Host:") + host + tu_string("\r\n"), HTTP_TIMEOUT);
	//	m_ns->write_string("Accept:*\r\n", HTTP_TIMEOUT);
	//	m_ns->write_string("Accept-Language: en\r\n", HTTP_TIMEOUT);
	//	m_ns->write_string("Accept-Encoding: gzip, deflate, chunked\r\n", HTTP_TIMEOUT);
	//	m_ns->write_string("Accept-Encoding: *\r\n", HTTP_TIMEOUT);
	//	m_ns->write_string("Proxy-Authenticate:prg\r\n", HTTP_TIMEOUT);
	//	m_ns->write_string("Proxy-Authorization:123\r\n", HTTP_TIMEOUT);
	m_ns->write_string("User-Agent:gameswf\r\n", HTTP_TIMEOUT);
	m_ns->write_string("Connection:Close\r\n", HTTP_TIMEOUT);

	m_ns->write_string("\r\n", HTTP_TIMEOUT);

	if (read_response() == false)
	{
		fprintf(stderr, "Couldn't find resource '%s', host '%s'\n", 
			uri.c_str(), host.c_str());
		delete m_ns;
		m_ns = NULL;
		return NULL;
	}

	return m_ns;
}
Exemple #12
0
int	main()
{
#if 1
	printf("sizeof(tu_string) == %d\n", sizeof(tu_string));

	array<tu_string>	storage;
	storage.resize(2);

	tu_string&	a = storage[0];
	tu_string&	b = storage[1];
	a = "test1";
	
	printf("&a = 0x%X, &b = 0x%X\n", int(&a), int(&b));

	printf("%s\n", a.c_str());

	assert(a == "test1");
	assert(a.length() == 5);

	a += "2";
	assert(a == "test12");

	a += "this is some more text";
	assert(a.length() == 28);

	assert(a[2] == 's');
	assert(a[3] == 't');
	assert(a[4] == '1');
	assert(a[5] == '2');
	assert(a[7] == 'h');
	assert(a[28] == 0);

	assert(b.length() == 0);
	assert(b[0] == 0);
	assert(b.c_str()[0] == 0);

	tu_string c = a + b;

	assert(c.length() == a.length());

	c.resize(2);
	assert(c == "te");
	assert(c == tu_string("te"));

	assert(tu_string("fourscore and sevent") == "fourscore and sevent");

	b = "#sacrificial lamb";

	// Test growing & shrinking.
	a = "";
	for (int i = 0; i < 1000; i++)
	{
		assert(a.length() == i);

		if (i == 8)
		{
			assert(a == "01234567");
		}
		else if (i == 27)
		{
			assert(a == "012345678901234567890123456");
		}

		a.resize(a.length() + 1);
		a[a.length() - 1] = '0' + (i % 10);
	}

	{for (int i = 999; i >= 0; i--)
	{
		a.resize(a.length() - 1);
		assert(a.length() == i);

		if (i == 8)
		{
			assert(a == "01234567");
		}
		else if (i == 27)
		{
			assert(a == "012345678901234567890123456");
		}
	}}

	// Test larger shrinking across heap/local boundary.
	a = "this is a string longer than 16 characters";
	a = "short";

	// Test larger expand across heap/local boundary.
	a = "another longer string...";

	assert(b == "#sacrificial lamb");

	test_hash();
	test_stringi();
	test_stringi_hash();

	test_unicode();

	// TODO: unit tests for array<>, string_hash<>
#endif

	test_hash_speed();

	return 0;
}
Exemple #13
0
namespace gameswf
{

void clears_tag_loaders();
void clear_disasm();

//
//	gameswf's statics
//

static glyph_provider* s_glyph_provider;
void set_glyph_provider(glyph_provider* gp)
{
    s_glyph_provider = gp;
}
glyph_provider* get_glyph_provider()
{
    return s_glyph_provider;
}

static bool	s_use_cached_movie_def = true;

// load movies from separate thread
static bool	s_use_separate_loader = true;

//
// file_opener callback stuff
//

static file_opener_callback	s_opener_function = NULL;

void	register_file_opener_callback(file_opener_callback opener)
// Host calls this to register a function for opening files,
// for loading movies.
{
    s_opener_function = opener;
}

static bool	s_use_cache_files = false;

void	set_use_cache_files(bool use_cache)
// Enable/disable attempts to read cache files when loading
// movies.
{
    s_use_cache_files = use_cache;
}


int player::s_player_count = 0;

// standard method map, this stuff should be high optimized

static stringi_hash<as_value>*	s_standard_method_map[BUILTIN_COUNT];
void clear_standard_method_map()
{
    for (int i = 0; i < BUILTIN_COUNT; i++)
    {
        if (s_standard_method_map[i])
        {
            delete s_standard_method_map[i];
        }
    }
}

bool get_builtin(builtin_object id, const tu_stringi& name, as_value* val)
{
    if (s_standard_method_map[id])
    {
        return s_standard_method_map[id]->get(name, val);
    }
    return false;
}

stringi_hash<as_value>* new_standard_method_map(builtin_object id)
{
    if (s_standard_method_map[id] == NULL)
    {
        s_standard_method_map[id] = new stringi_hash<as_value>;
    }
    return s_standard_method_map[id];
}

void standard_method_map_init()
{
    // setup builtin methods
    stringi_hash<as_value>* map;

    // as_object builtins
    map = new_standard_method_map(BUILTIN_OBJECT_METHOD);
    map->add("addProperty", as_object_addproperty);
    map->add("registerClass", as_object_registerclass);
    map->add("hasOwnProperty", as_object_hasownproperty);
    map->add("watch", as_object_watch);
    map->add("unwatch", as_object_unwatch);

    // flash9
    map->add("addEventListener", as_object_add_event_listener);

    // for debugging
#ifdef _DEBUG
    map->add("dump", as_object_dump);
#endif

    // as_number builtins
    map = new_standard_method_map(BUILTIN_NUMBER_METHOD);
    map->add("toString", as_number_to_string);
    map->add("valueOf", as_number_valueof);

    // as_boolean builtins
    map = new_standard_method_map(BUILTIN_BOOLEAN_METHOD);
    map->add("toString", as_boolean_to_string);
    map->add("valueOf", as_boolean_valueof);

    // as_string builtins
    map = new_standard_method_map(BUILTIN_STRING_METHOD);
    map->add("toString", string_to_string);
    map->add("fromCharCode", string_from_char_code);
    map->add("charCodeAt", string_char_code_at);
    map->add("concat", string_concat);
    map->add("indexOf", string_index_of);
    map->add("lastIndexOf", string_last_index_of);
    map->add("slice", string_slice);
    map->add("split", string_split);
    map->add("substring", string_substring);
    map->add("substr", string_substr);
    map->add("toLowerCase", string_to_lowercase);
    map->add("toUpperCase", string_to_uppercase);
    map->add("charAt", string_char_at);
    map->add("length", as_value(string_length, as_value()));

    // sprite_instance builtins
    map = new_standard_method_map(BUILTIN_SPRITE_METHOD);
    map->add("play", sprite_play);
    map->add("stop", sprite_stop);
    map->add("gotoAndStop", sprite_goto_and_stop);
    map->add("gotoAndPlay", sprite_goto_and_play);
    map->add("nextFrame", sprite_next_frame);
    map->add("prevFrame", sprite_prev_frame);
    map->add("getBytesLoaded", sprite_get_bytes_loaded);
    map->add("getBytesTotal", sprite_get_bytes_total);
    map->add("swapDepths", sprite_swap_depths);
    map->add("duplicateMovieClip", sprite_duplicate_movieclip);
    map->add("getDepth", sprite_get_depth);
    map->add("createEmptyMovieClip", sprite_create_empty_movieclip);
    map->add("removeMovieClip", sprite_remove_movieclip);
    map->add("hitTest", sprite_hit_test);
    map->add("startDrag", sprite_start_drag);
    map->add("stopDrag", sprite_stop_drag);
    map->add("loadMovie", sprite_loadmovie);
    map->add("unloadMovie", sprite_unloadmovie);
    map->add("getNextHighestDepth", sprite_getnexthighestdepth);
    map->add("createTextField", sprite_create_text_field);
    map->add("attachMovie", sprite_attach_movie);
    map->add("localToGlobal", sprite_local_global);
    map->add("globalToLocal", sprite_global_local);
    map->add("getRect", sprite_get_rect);
    map->add("getBounds", sprite_get_bounds);
    map->add("setMask", sprite_set_mask);

    // drawing API
    map->add("beginFill", sprite_begin_fill);
    map->add("endFill", sprite_end_fill);
    map->add("lineTo", sprite_line_to);
    map->add("moveTo", sprite_move_to);
    map->add("curveTo", sprite_curve_to);
    map->add("clear", sprite_clear);
    map->add("lineStyle", sprite_line_style);

    // gameSWF extension
    // reset root FPS
    map->add("setFPS", sprite_set_fps);

    // gameSWF extension
    // return true if movieclip is in PLAY state
    map->add("getPlayState", sprite_get_play_state);

    // Flash9
    map->add("addFrameScript", sprite_add_script);

}

// Standard property lookup.

static stringi_hash<as_standard_member>	s_standard_property_map;
void clear_standard_property_map()
{
    s_standard_property_map.clear();
}

const char* get_gameswf_version()
{
#ifdef WIN32
    static tu_string s_gameswf_version("WIN "__DATE__" "__TIME__);
#else
    static tu_string s_gameswf_version("LINUX "__DATE__" "__TIME__);
#endif

    return s_gameswf_version.c_str();
}

// dynamic library stuff, for sharing DLL/shared library among different movies.

static string_hash<tu_loadlib*> s_shared_libs;
string_hash<tu_loadlib*>* get_shared_libs()
{
    return &s_shared_libs;
}

void clear_shared_libs()
{
    for (string_hash<tu_loadlib*>::iterator it = s_shared_libs.begin();
            it != s_shared_libs.end(); ++it)
    {
        delete it->second;
    }
    s_shared_libs.clear();
}

struct registered_type_node
{
    registered_type_node(const tu_string& classname, gameswf_module_init type_init_func) :
        m_next(NULL),
        m_classname(classname),
        m_type_init(type_init_func)
    {
    }

    registered_type_node *m_next;
    tu_string             m_classname;
    gameswf_module_init   m_type_init;
};

static registered_type_node* s_registered_types = NULL;

void register_type_handler(const tu_string& type_name, gameswf_module_init type_init_func )
{
    registered_type_node** node = &s_registered_types;
    while(*node)
    {
        node = &((*node)->m_next);
    }
    *node = new registered_type_node(type_name, type_init_func);
}

void clear_registered_type_handlers()
{
    registered_type_node *curr = s_registered_types;
    s_registered_types = NULL;
    while(curr)
    {
        registered_type_node *next = curr->m_next;
        delete curr;
        curr = next;
    }
}

gameswf_module_init find_type_handler(const tu_string& type_name)
{
    registered_type_node *node = s_registered_types;
    while(node)
    {
        if (node->m_classname == type_name)
        {
            return node->m_type_init;
        }
        node = node->m_next;
    }
    return NULL;
}

// External interface.

static fscommand_callback	s_fscommand_handler = NULL;

fscommand_callback	get_fscommand_callback()
{
    return s_fscommand_handler;
}

void	register_fscommand_callback(fscommand_callback handler)
{
    s_fscommand_handler = handler;
}

as_standard_member	get_standard_member(const tu_stringi& name)
{
    if (s_standard_property_map.size() == 0)
    {
        s_standard_property_map.set_capacity(int(AS_STANDARD_MEMBER_COUNT));

        s_standard_property_map.add("_x", M_X);
        s_standard_property_map.add("_y", M_Y);
        s_standard_property_map.add("_xscale", M_XSCALE);
        s_standard_property_map.add("_yscale", M_YSCALE);
        s_standard_property_map.add("_currentframe", M_CURRENTFRAME);
        s_standard_property_map.add("_totalframes", M_TOTALFRAMES);
        s_standard_property_map.add("_alpha", M_ALPHA);
        s_standard_property_map.add("_visible", M_VISIBLE);
        s_standard_property_map.add("_width", M_WIDTH);
        s_standard_property_map.add("_height", M_HEIGHT);
        s_standard_property_map.add("_rotation", M_ROTATION);
        s_standard_property_map.add("_target", M_TARGET);
        s_standard_property_map.add("_framesloaded", M_FRAMESLOADED);
        s_standard_property_map.add("_name", M_NAME);
        s_standard_property_map.add("_droptarget", M_DROPTARGET);
        s_standard_property_map.add("_url", M_URL);
        s_standard_property_map.add("_highquality", M_HIGHQUALITY);
        s_standard_property_map.add("_focusrect", M_FOCUSRECT);
        s_standard_property_map.add("_soundbuftime", M_SOUNDBUFTIME);
        s_standard_property_map.add("_xmouse", M_XMOUSE);
        s_standard_property_map.add("_ymouse", M_YMOUSE);
        s_standard_property_map.add("_parent", M_PARENT);
        s_standard_property_map.add("text", M_TEXT);
        s_standard_property_map.add("textWidth", M_TEXTWIDTH);
        s_standard_property_map.add("textColor", M_TEXTCOLOR);
        s_standard_property_map.add("border", M_BORDER);
        s_standard_property_map.add("multiline", M_MULTILINE);
        s_standard_property_map.add("wordWrap", M_WORDWRAP);
        s_standard_property_map.add("type", M_TYPE);
        s_standard_property_map.add("backgroundColor", M_BACKGROUNDCOLOR);
        s_standard_property_map.add("_this", M_THIS);
        s_standard_property_map.add("this", MTHIS);
        s_standard_property_map.add("_root", M_ROOT);
        s_standard_property_map.add(".", MDOT);
        s_standard_property_map.add("..", MDOT2);
        s_standard_property_map.add("_level0", M_LEVEL0);
        s_standard_property_map.add("_global", M_GLOBAL);
        s_standard_property_map.add("enabled", M_ENABLED);
        s_standard_property_map.add("password", M_PASSWORD);
        s_standard_property_map.add("onMouseMove", M_MOUSE_MOVE);
    }

    as_standard_member	result = M_INVALID_MEMBER;
    s_standard_property_map.get(name, &result);

    return result;
}

//
// properties by number
//

static const tu_string	s_property_names[] =
{
    tu_string("_x"),
    tu_string("_y"),
    tu_string("_xscale"),
    tu_string("_yscale"),
    tu_string("_currentframe"),
    tu_string("_totalframes"),
    tu_string("_alpha"),
    tu_string("_visible"),
    tu_string("_width"),
    tu_string("_height"),
    tu_string("_rotation"),
    tu_string("_target"),
    tu_string("_framesloaded"),
    tu_string("_name"),
    tu_string("_droptarget"),
    tu_string("_url"),
    tu_string("_highquality"),
    tu_string("_focusrect"),
    tu_string("_soundbuftime"),
    tu_string("mysteryquality"), //tu_string("@@ mystery quality member"),  //this seems like a stupid bug to me . . . but I don't want it accessing the heap yet.
    tu_string("_xmouse"),
    tu_string("_ymouse"),
};

as_value	get_property(as_object* obj, int prop_number)
{
    as_value	val;
    if (prop_number >= 0 && prop_number < int(sizeof(s_property_names)/sizeof(s_property_names[0])))
    {
        obj->get_member(s_property_names[prop_number], &val);
    }
    else
    {
        log_error("error: invalid property query, property number %d\n", prop_number);
    }
    return val;
}

void	set_property(as_object* obj, int prop_number, const as_value& val)
{
    if (prop_number >= 0 && prop_number < int(sizeof(s_property_names)/sizeof(s_property_names[0])))
    {
        obj->set_member(s_property_names[prop_number], val);
    }
    else
    {
        log_error("error: invalid set_property, property number %d\n", prop_number);
    }
}

//
//	player
//

player::player() :
    m_force_realtime_framerate(false),
    m_log_bitmap_info(false)
{
    m_global = new as_object(this);

    action_init();

    if (s_player_count == 0)
    {
        // timer should be inited only once
        tu_timer::init_timer();

        standard_method_map_init();
    }

    ++s_player_count;

    // set startup random position
    Uint64 t = tu_timer::get_systime();
    t &= 0xFF;	// truncate
    for (unsigned int i = 0; i < t; i++)
    {
        tu_random::next_random();
    }

}

player::~player()
{
    // Clean up gameswf as much as possible, so valgrind will help find actual leaks.
    // Maximum release of resources.  Calls clear_library() and
    // fontlib::clear(), and also clears some extra internal stuff
    // that may have been allocated (e.g. global ActionScript
    // objects).  This should get all gameswf structures off the
    // heap, with the exception of any objects that are still
    // referenced by the host program and haven't had drop_ref()
    // called on them.

    m_current_root = NULL;
    m_global = NULL;
    --s_player_count;

    clear_heap();

    gameswf_engine_mutex().lock();

    clear_library();

    // Clear shared stuff only when all players are deleted
    if (s_player_count == 0)
    {
        clears_tag_loaders();
        clear_shared_libs();
        clear_registered_type_handlers();
        clear_standard_method_map();
        clear_disasm();
        delete s_glyph_provider;
        s_glyph_provider = NULL;
    }

    gameswf_engine_mutex().unlock();

    action_clear();
}

void player::set_flash_vars(const tu_string& param)
// Allow pass user variables to Flash
{
    m_flash_vars = param;
}

void player::verbose_action(bool val)
{
    set_verbose_action(val);
}

void player::verbose_parse(bool val)
{
    set_verbose_parse(val);
}

void	as_global_trace(const fn_call& fn);
void	player::action_init()
// Create/hook built-ins.
{
    //
    // global init
    //

    m_heap.set(m_global.get_ptr(), false);
    m_global->builtin_member("trace", as_global_trace);
    m_global->builtin_member("Object", as_global_object_ctor);
    m_global->builtin_member("Sound", as_global_sound_ctor);

    m_global->builtin_member("Array", new as_global_array(this));
    m_global->builtin_member("MovieClip", as_global_movieclip_ctor);
    m_global->builtin_member("TextField", as_global_textfield_ctor);
    m_global->builtin_member("TextFormat", as_global_textformat_ctor);
    m_global->builtin_member("SharedObject", new as_sharedobject(this));
    m_global->builtin_member("Mouse", new as_mouse(this));

    //			m_global->set_member("XML", as_value(xml_new));
    m_global->builtin_member("MovieClipLoader", as_global_mcloader_ctor);
    m_global->builtin_member("String", get_global_string_ctor(this));
    m_global->builtin_member("Number", as_global_number_ctor);
    m_global->builtin_member("Boolean", as_global_boolean_ctor);
    m_global->builtin_member("Color", as_global_color_ctor);
    m_global->builtin_member("Date", as_global_date_ctor);
    m_global->builtin_member("Selection", selection_init(this));

    as_object * capabilities = new as_object(this);
    capabilities->set_member( "version", "WIN 9,0,45,0" );
    m_global->builtin_member("Capabilities", capabilities);

#if TU_ENABLE_NETWORK == 1
    m_global->builtin_member("XMLSocket", as_global_xmlsock_ctor);
    m_global->builtin_member("LoadVars", as_global_loadvars_ctor);
#endif

    // ASSetPropFlags
    m_global->builtin_member("ASSetPropFlags", as_global_assetpropflags);

    // for video
    m_global->builtin_member("NetStream", as_global_netstream_ctor);
    m_global->builtin_member("NetConnection", as_global_netconnection_ctor);

    m_global->builtin_member("math", math_init(this));
    m_global->builtin_member("Key", key_init(this));
    m_global->builtin_member("AsBroadcaster", broadcaster_init(this));
    m_global->builtin_member("flash", flash_init(this));

    // global builtins functions
    m_global->builtin_member("setInterval",  as_global_setinterval);
    m_global->builtin_member("clearInterval",  as_global_clearinterval);
    m_global->builtin_member("setTimeout",  as_global_settimeout);
    m_global->builtin_member("clearTimeout",  as_global_clearinterval);
    m_global->builtin_member("getVersion",  as_global_get_version);
    m_global->builtin_member("parseFloat",  as_global_parse_float);
    m_global->builtin_member("parseInt",  as_global_parse_int);
    m_global->builtin_member("isNaN",  as_global_isnan);
    m_global->builtin_member("$version", as_value(as_global_get_version, as_value()));
    m_global->builtin_member("updateAfterEvent", as_global_update_after_event);
}


void	player::action_clear()
{
    if ( 0 == s_player_count )
    {
        clear_standard_property_map();
    }
}

as_object* player::get_global() const
{
    return m_global.get_ptr();
}

void player::notify_key_object(key::code k, bool down)
{
    as_value	kval;
    as_object* global = get_global();
    global->get_member("Key", &kval);
    as_key*	ko = cast_to<as_key>(kval.to_object());
    if (ko)
    {
        if (down) ko->set_key_down(k);
        else ko->set_key_up(k);
    }
    else
    {
        log_error("gameswf::notify_key_event(): no Key built-in\n");
    }
}

root* player::get_root()
{
    // on exit m_current_root may be NULL
//		assert(m_current_root.get_ptr() != NULL);
    return m_current_root.get_ptr();
}

character*	player::get_root_movie() const
{
    if (m_current_root != NULL)
    {
        return m_current_root->get_root_movie();
    }
    return NULL;
}

void player::notify_key_event(key::code k, bool down)
{
    m_current_root->notify_key_event(this, k, down);
}

void player::set_root(root* m)
{
    assert(m != NULL);
    m_current_root = m;
}

const char* player::get_workdir() const
{
    return m_workdir.c_str();
}

void player::set_workdir(const char* dir)
{
    assert(dir != NULL);
    m_workdir = dir;
}

// library stuff, for sharing resources among different movies.
string_hash<gc_ptr<character_def> >* player::get_chardef_library()
{
    return &m_chardef_library;
}

const char* player::get_root_filename(const character_def* rdef)
// get filename by root movie definition
{
    for (string_hash<gc_ptr<character_def> >::iterator it = m_chardef_library.begin();
            it != m_chardef_library.end(); ++it)
    {
        if (it->second == rdef)
        {
            return it->first.c_str();
        }
    }
    return NULL;
}

void player::clear_library()
// Drop all library references to movie_definitions, so they
// can be cleaned up.
{
    for (string_hash<gc_ptr<character_def> >::iterator it =
                m_chardef_library.begin(); it != m_chardef_library.end(); ++it)
    {
        if (gc_collector::debug_get_ref_count(it->second) > 1)
        {
            printf("memory leaks is found out: on exit movie_definition_sub ref_count > 1\n");
            printf("this = 0x%p, ref_count = %d\n", it->second.get_ptr(),
                   gc_collector::debug_get_ref_count(it->second));

            // to detect memory leaks
            while (gc_collector::debug_get_ref_count(it->second) > 1) {
                gc_collector::debug_decrement_ref_count(it->second);
            }
        }
    }
    m_chardef_library.clear();
}

void	ensure_loaders_registered();
movie_definition*	player::create_movie(const char* filename)
{
    assert(filename);

    // Is the movie already in the library?
    if (s_use_cached_movie_def)
    {
        gc_ptr<character_def>	m;
        get_chardef_library()->get(filename, &m);
        if (m != NULL)
        {
            // Return cached movie.
            return cast_to<movie_definition>(m.get_ptr());
        }
    }

    if (s_opener_function == NULL)
    {
        // Don't even have a way to open the file.
        log_error("error: no file opener function; can't create movie.	"
                  "See gameswf::register_file_opener_callback\n");
        return NULL;
    }

    tu_file* in = s_opener_function(filename);
    if (in == NULL)
    {
        log_error("failed to open '%s'; can't create movie.\n", filename);
        return NULL;
    }
    else if (in->get_error())
    {
        log_error("error: file opener can't open '%s'\n", filename);
        delete in;
        return NULL;
    }

    ensure_loaders_registered();

    movie_def_impl*	m = new movie_def_impl(this, DO_LOAD_BITMAPS, DO_LOAD_FONT_SHAPES);

    if (s_use_cached_movie_def)
    {
        get_chardef_library()->add(filename, m);
    }

    m->read(in);

    // "in" will be deleted after termination of the loader thread
    //	delete in;

    if (m && s_use_cache_files)
    {
        // Try to load a .gsc file.
        tu_string	cache_filename(filename);
        cache_filename += ".gsc";
        tu_file*	cache_in = s_opener_function(cache_filename.c_str());
        if (cache_in == NULL
                || cache_in->get_error() != TU_FILE_NO_ERROR)
        {
            // Can't open cache file; don't sweat it.
            IF_VERBOSE_PARSE(log_msg("note: couldn't open cache file '%s'\n", cache_filename.c_str()));
        }
        else
        {
            // Load the cached data.
            m->input_cached_data(cache_in);
        }

        delete cache_in;
    }

    return m;
}

gc_ptr<root> player::load_file(const char* infile)
// Load the actual movie.
{
    gc_ptr<gameswf::movie_definition>	md = create_movie(infile);
    if (md == NULL)
    {
        fprintf(stderr, "error: can't create a movie from '%s'\n", infile);
        return NULL;
    }

    gc_ptr<gameswf::root>	m = md->create_instance();
    if (m == NULL)
    {
        fprintf(stderr, "error: can't create movie instance\n");
        return NULL;
    }

    int	movie_version = m->get_movie_version();

#ifdef _DEBUG
    log_msg("Playing %s, swf version %d\n", infile, movie_version);
#else
    IF_VERBOSE_PARSE(log_msg("Playing %s, swf version %d\n", infile, movie_version));
#endif

    return m;
}

const bool player::get_force_realtime_framerate() const
{
    return m_force_realtime_framerate;
}

void player::set_force_realtime_framerate(const bool force_realtime_framerate)
{
    m_force_realtime_framerate = force_realtime_framerate;
}

// garbage collector

void player::set_alive(as_object* obj)
{
    m_heap.set(obj, false);
}

bool player::is_garbage(as_object* obj)
{
    bool is_garbage = false;
    m_heap.get(obj, &is_garbage);
    return is_garbage;
}

void player::clear_heap()
{
    for (hash<gc_ptr<as_object>, bool>::iterator it = m_heap.begin();
            it != m_heap.end(); ++it)
    {
        as_object* obj = it->first.get_ptr();
        if (obj)
        {
            if (gc_collector::debug_get_ref_count(obj) > 1)
            {
                hash<as_object*, bool> visited_objects;
                obj->clear_refs(&visited_objects, obj);
            }
        }
    }
    m_heap.clear();
}

void player::set_as_garbage()
{
    for (hash<gc_ptr<as_object>, bool>::iterator it = m_heap.begin();
            it != m_heap.end(); ++it)
    {
        as_object* obj = it->first.get_ptr();
        if (obj)
        {
            m_heap.set(obj, true);
        }
    }
}

void player::clear_garbage()
{
    m_global->this_alive();
    for (hash<gc_ptr<as_object>, bool>::iterator it = m_heap.begin();
            it != m_heap.end(); ++it)
    {
        as_object* obj = it->first.get_ptr();
        if (obj)
        {
            if (it->second)	// is garbage ?
            {
                if (gc_collector::debug_get_ref_count(obj) > 1)	// is in heap only ?
                {
                    hash<as_object*, bool> visited_objects;
                    obj->clear_refs(&visited_objects, obj);
                }
                m_heap.erase(obj);
            }
        }
    }
}

bool player::use_separate_thread()
{
    return s_use_separate_loader;
}

void player::set_separate_thread(bool flag)
{
    s_use_separate_loader = flag;
}

}
	bool get_fontfile(const char* font_name, tu_string& file_name, bool is_bold, bool is_italic)
	// gets font file name by font name
	{

		if (font_name == NULL)
		{
			return false;
		}

#ifdef _WIN32

		//Vitaly: I'm not sure that this code works on all versions of Windows

		tu_stringi fontname = font_name;
		if (is_bold)
		{
			fontname += " Bold";
		}
		if (is_italic)
		{
			fontname +=  " Italic";
		}
		fontname += " (TrueType)";

		HKEY hKey;

		// try WinNT
		DWORD retCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
			"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 
			0, 
			KEY_ALL_ACCESS,
			&hKey);

		if (retCode != ERROR_SUCCESS)
		{
			// try Windows
			retCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
				"Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", 
				0, 
				KEY_ALL_ACCESS,
				&hKey);

			if (retCode != ERROR_SUCCESS)
			{
				return false;
			}
		}

		// Get the value of the 'windir' environment variable.
		tu_string windir(getenv("WINDIR"));

		// Get value count. 
		DWORD    cValues;              // number of values for key 
		retCode = RegQueryInfoKey(
			hKey,	// key handle 
			NULL,	// buffer for class name 
			NULL,	// size of class string 
			NULL,	// reserved 
			NULL,	// number of subkeys 
			NULL,	// longest subkey size 
			NULL,	// longest class string 
			&cValues,	// number of values for this key 
			NULL,	// longest value name 
			NULL,	// longest value data 
			NULL,	// security descriptor 
			NULL);	// last write time 

		// Enumerate the key values. 
		BYTE szValueData[MAX_PATH];
		TCHAR  achValue[MAX_PATH]; 
		for (DWORD i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) 
		{ 
			DWORD cchValue = MAX_PATH; 
			DWORD dwValueDataSize = sizeof(szValueData) - 1;
			achValue[0] = '\0'; 
			retCode = RegEnumValueA(hKey, i, 
				achValue, 
				&cchValue, 
				NULL, 
				NULL,
				szValueData,
				&dwValueDataSize);

			if (retCode == ERROR_SUCCESS) 
			{ 
				if (fontname == (char*) achValue)
				{
					file_name = windir + tu_string("\\Fonts\\") + (char*) szValueData;
					RegCloseKey(hKey);
					return true;
				}
			} 
		}

		RegCloseKey(hKey);
		return false;
 
		// font file is not found, take default value - 'Times New Roman'
/*		file_name = windir + tu_string("\\Fonts\\Times");
		if (is_bold && is_italic)
		{
			file_name += "BI";
		}
		else
		if (is_bold)
		{
			file_name +=  "B";
		}
		else
		if (is_italic)
		{
			file_name +=  "I";
		}
		file_name += ".ttf";
		log_error("can't find font file for '%s'\nit's used '%s' file\n", fontname.c_str(), file_name.c_str());

		return true;*/

#else

	//TODO for Linux

	// hack
	if (strstr(font_name, "Times New Roman"))
	{
		file_name = "/usr/share/fonts/truetype/times";
		if (is_bold && is_italic)
		{
			file_name += "bi";
		}
		else
		if (is_bold)
		{
			file_name +=  "b";
		}
		else
		if (is_italic)
		{
			file_name +=  "b";
		}
		file_name += ".ttf";

		return true;
	}

	return false;


#endif
	}