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) ); } }
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) ); } }
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(¶m); unescape_url_component(&value); if (param.length()) { m_req.add_param(param, value); } } }
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); }
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; }
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; }
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; }
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; }
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 }