/** * Get absolute path to the specified relative path. This path will typically * point to the to client data directory (which is usually located in the user's * home/appdata directory), but depending on the specified mode, extra actions * may be performed. These ensure that if you're trying to access a file that * does not yet exist in the client data directory, it will be read from the * client installation directory instead (unless it's being appended to, in * which case it will be copied to the client data directory first). * * Generally, you should almost always use this when you need to construct a * path, or use one of the many @ref file_wrapper_functions. * @param fname * The file path. * @param mode * File mode. * @return * The absolute path. Must be freed. */ char *file_path(const char *path, const char *mode) { bool is_write, is_append; StringBuffer *sb; char version[MAX_BUF], client_path[HUGE_BUF], *new_path; HARD_ASSERT(path != NULL); HARD_ASSERT(mode != NULL); SOFT_ASSERT_RC(path[0] != '/', estrdup(path), "Path is already absolute: %s", path); sb = stringbuffer_new(); stringbuffer_append_printf(sb, "%s/.atrinik/%s/%s", get_config_dir(), package_get_version_partial(VS(version)), path); new_path = stringbuffer_sub(sb, 0, 0); is_write = is_append = false; if (strchr(mode, 'w') != NULL) { is_write = true; } else if (strchr(mode, '+') != NULL || strchr(mode, 'a') != NULL) { is_append = true; } if (is_write || is_append) { if (access(new_path, W_OK) != 0) { char *dirname; /* Ensure directories exist if we're going to use this path for * writing/appending. */ dirname = path_dirname(new_path); mkdir_recurse(dirname); efree(dirname); if (is_append) { get_data_dir_file(VS(client_path), path); copy_file(client_path, new_path); } } } else { if (access(new_path, R_OK) != 0) { get_data_dir_file(VS(client_path), path); stringbuffer_seek(sb, 0); stringbuffer_append_string(sb, client_path); } } efree(new_path); return stringbuffer_finish(sb); }
void object_redraw(object *op) { object *env; HARD_ASSERT(op != NULL); if (op->env == NULL) { return; } env = op->env; if (env == cpl.sack) { env = cpl.sack->env; } if (env == cpl.interface) { interface_redraw(); } else if (env == cpl.below) { widget_redraw_type_id(INVENTORY_ID, "below"); } else { widget_redraw_type_id(INVENTORY_ID, "main"); /* TODO: This could be more sophisticated... */ WIDGET_REDRAW_ALL(QUICKSLOT_ID); } }
/** * Removes all the files in the specified directory. * * @param dir * The directory. * @param path * Path to the directory. */ static void _rmrf (DIR *dir, const char *path) { HARD_ASSERT(dir != NULL); struct dirent *file; while ((file = readdir(dir)) != NULL) { if (strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0) { continue; } char buf[HUGE_BUF]; snprintf(VS(buf), "%s/%s", path, file->d_name); DIR *dir2 = opendir(buf); if (dir2 != NULL) { _rmrf(dir2, buf); closedir(dir2); rmdir(buf); } else { unlink(buf); } } }
/** * Free the specified server certificate information structure. * * @param info * What to free. */ static void metaserver_cert_free (server_cert_info_t *info) { HARD_ASSERT(info != NULL); if (info->name != NULL) { efree(info->name); } if (info->hostname != NULL) { efree(info->hostname); } if (info->ipv4_address != NULL) { efree(info->ipv4_address); } if (info->ipv6_address != NULL) { efree(info->ipv6_address); } if (info->pubkey != NULL) { efree(info->pubkey); } efree(info); }
/** * Free the specified sprite cache entry. * @param cache */ static void sprite_cache_free (sprite_cache_t *cache) { HARD_ASSERT(cache != NULL); efree(cache->name); SDL_FreeSurface(cache->surface); efree(cache); }
/** * Updates all network graph widgets with new data. * @param type * The network graph type. * @param traffic * The traffic type (tx/rx). * @param bytes * Bytes. * @note This function is thread-safe. */ void network_graph_update(int type, int traffic, size_t bytes) { HARD_ASSERT(type >= 0 && type < NETWORK_GRAPH_TYPE_MAX); HARD_ASSERT(traffic >= 0 && traffic < NETWORK_GRAPH_TRAFFIC_MAX); if (network_graph_mutex == NULL) { return; } network_graph_work_t *work = ecalloc(1, sizeof(*work)); work->type = type; work->traffic = traffic; work->bytes = bytes; SDL_LockMutex(network_graph_mutex); LL_PREPEND(work_queue, work); SDL_UnlockMutex(network_graph_mutex); }
/** * Construct debug information about leaked chunks in the specified pool. * * @param pool * Memory pool. * @param sb * StringBuffer instance to store the information in. */ static void mempool_leak_info(mempool_struct *pool, StringBuffer *sb) { size_t chunksize_real, nrof_arrays, i, j; char buf[HUGE_BUF]; mempool_puddle_struct *puddle; mempool_chunk_struct *chunk; void *data; HARD_ASSERT(pool != NULL); HARD_ASSERT(sb != NULL); #ifndef NDEBUG if (pool->debugger == NULL) { #else { #endif snprintf(VS(buf), "no debug information available"); }
/** * Create a new sprite cache entry. * * @param name * Name of the cache entry. * @return * Created sprite entry. */ static sprite_cache_t * sprite_cache_create (const char *name) { HARD_ASSERT(name != NULL); sprite_cache_t *cache = ecalloc(1, sizeof(*cache)); cache->name = estrdup(name); cache->last_used = time(NULL); return cache; }
/** * Create a path to the per-server settings directory. * @param path * Path inside the per-server settings directory. * @return * New path. Must be freed. */ char *file_path_server(const char *path) { StringBuffer *sb; HARD_ASSERT(path != NULL); sb = file_path_server_internal(); stringbuffer_append_printf(sb, ".common/%s", path); return stringbuffer_finish(sb); }
/** * Verify resolved address of a server against the server's metaserver * certificate. * * @param server * Server to verify. * @param host * Host address. * @return * True if the resolved address is equal to the one in the certificate, * false otherwise. */ bool metaserver_cert_verify_host (server_struct *server, const char *host) { HARD_ASSERT(server != NULL); HARD_ASSERT(host != NULL); /* No certificate, nothing to verify. */ if (server->cert_info == NULL) { return true; } struct sockaddr_storage addr; SOFT_ASSERT_RC(socket_host2addr(host, &addr), false, "Failed to convert host to IP address"); switch (addr.ss_family) { case AF_INET: if (strcmp(host, server->cert_info->ipv4_address) != 0) { LOG(ERROR, "!!! Certificate IPv4 address error: %s != %s !!!", host, server->cert_info->ipv4_address); return false; } break; case AF_INET6: if (strcmp(host, server->cert_info->ipv6_address) != 0) { LOG(ERROR, "!!! Certificate IPv6 address error: %s != %s !!!", host, server->cert_info->ipv6_address); return false; } break; default: LOG(ERROR, "!!! Unknown address family %u !!!", addr.ss_family); return false; } return true; }
void labels_ref_solve(t_dstr *bcode, t_asm_bytecode const *b) { t_label_ref const *ref; uint32_t const *loc; ref = VECTOR_IT(b->labels_ref); while (VECTOR_NEXT(b->labels_ref, ref)) { loc = ft_hmapget(b->labels_loc, ref->name).value; HARD_ASSERT(loc != NULL); put_loc(bcode, ref->offset, *loc - ref->instr_begin, ref->short_value); } }
/** * Recursively remove a directory and its contents. * * Effectively same as 'rf -rf path'. * * @param path * What to remove. */ void rmrf(const char *path) { HARD_ASSERT(path != NULL); DIR *dir = opendir(path); if (dir == NULL) { return; } _rmrf(dir, path); closedir(dir); rmdir(path); }
/** * Open a new socket. * @param csock * Socket to open. * @param host * Host to connect to. * @param port * Port to connect to. * @param secure * Whether the port is the secure port. * @return * True on success, false on failure. */ bool client_socket_open (client_socket_t *csock, const char *host, int port, bool secure) { HARD_ASSERT(csock != NULL); HARD_ASSERT(host != NULL); csock->sc = socket_create(host, port, secure, SOCKET_ROLE_CLIENT, false); if (csock->sc == NULL) { return false; } if (!socket_connect(csock->sc)) { goto error; } if (!socket_opt_linger(csock->sc, true, 5)) { goto error; } if (setting_get_int(OPT_CAT_CLIENT, OPT_MINIMIZE_LATENCY)) { if (!socket_opt_ndelay(csock->sc, true)) { goto error; } } if (!socket_opt_recv_buffer(csock->sc, 65535)) { goto error; } return true; error: socket_destroy(csock->sc); csock->sc = NULL; return false; }
/** * Find a sprite in the sprite cache. * * @param name * Name of the sprite to find. * @return * Sprite if found, NULL otherwise. */ static sprite_cache_t * sprite_cache_find (const char *name) { HARD_ASSERT(name != NULL); sprite_cache_t *cache; HASH_FIND_STR(sprites_cache, name, cache); if (cache != NULL) { cache->last_used = time(NULL); } return cache; }
/** * Create a path to the per-player settings directory. * @param path * Path inside the per-player settings directory. * @return * New path. Must be freed. */ char *file_path_player(const char *path) { StringBuffer *sb; HARD_ASSERT(path != NULL); sb = file_path_server_internal(); SOFT_ASSERT_LABEL(*cpl.account != '\0', done, "Account name is empty."); SOFT_ASSERT_LABEL(*cpl.name != '\0', done, "Player name is empty."); stringbuffer_append_printf(sb, "%s/%s/%s", cpl.account, cpl.name, path); done: return stringbuffer_finish(sb); }
/** * Close a client socket. * @param csock * Socket to close. */ void client_socket_close(client_socket_t *csock) { HARD_ASSERT(csock != NULL); SDL_LockMutex(socket_mutex); if (csock->sc != NULL) { socket_destroy(csock->sc); csock->sc = NULL; } abort_thread = 1; /* Poke anyone waiting at a cond */ SDL_CondSignal(input_buffer_cond); SDL_CondSignal(output_buffer_cond); SDL_UnlockMutex(socket_mutex); }
bool parse_opt_ui(t_parse_argv *argv) { t_sub val; if (!ARGV_HAS_VALUE(&argv->args)) argv->ui_type = UI_NCURSES; else { if (!ft_argv_arg(&argv->args, &val)) HARD_ASSERT(false); if (SUB_EQU(val, SUBC("ncurses"))) argv->ui_type = UI_NCURSES; else if (SUB_EQU(val, SUBC("debug"))) argv->ui_type = UI_DEBUG; else { PARSE_ARGV_ERR("Invalid ui mode '%ts'", val); return (false); } } return (true); }
/** * Free the specified metaserver server node. * * @param server * Node to free. */ static void metaserver_free (server_struct *server) { HARD_ASSERT(server != NULL); if (server->hostname != NULL) { efree(server->hostname); } if (server->name != NULL) { efree(server->name); } if (server->version != NULL) { efree(server->version); } if (server->desc != NULL) { efree(server->desc); } if (server->cert_pubkey != NULL) { efree(server->cert_pubkey); } if (server->cert != NULL) { efree(server->cert); } if (server->cert_sig != NULL) { efree(server->cert_sig); } if (server->cert_info != NULL) { metaserver_cert_free(server->cert_info); } efree(server); }
void socket_send_packet(struct packet_struct *packet) { HARD_ASSERT(packet != NULL); if (csocket.sc == NULL) { packet_free(packet); return; } packet_struct *packet_meta = packet_new(0, 4, 0); if (socket_is_secure(csocket.sc)) { bool checksum_only = !socket_crypto_client_should_encrypt(packet->type); packet = socket_crypto_encrypt(csocket.sc, packet, packet_meta, checksum_only); if (packet == NULL) { /* Logging already done. */ cpl.state = ST_START; return; } } else { packet_append_uint16(packet_meta, packet->len + 1); packet_append_uint8(packet_meta, packet->type); } command_buffer *buf1 = command_buffer_new(packet_meta->len, packet_meta->data); packet_free(packet_meta); command_buffer *buf2 = command_buffer_new(packet->len, packet->data); packet_free(packet); SDL_LockMutex(output_buffer_mutex); command_buffer_enqueue(buf1, &output_queue_start, &output_queue_end); command_buffer_enqueue(buf2, &output_queue_start, &output_queue_end); SDL_CondSignal(output_buffer_cond); SDL_UnlockMutex(output_buffer_mutex); }
/** * Parse metaserver 'server' node. * * @param node * Node to parse. */ static void parse_metaserver_node (xmlNodePtr node) { HARD_ASSERT(node != NULL); server_struct *server = ecalloc(1, sizeof(*server)); server->port_crypto = -1; server->is_meta = true; for (xmlNodePtr tmp = node->children; tmp != NULL; tmp = tmp->next) { if (!parse_metaserver_data_node(tmp, server)) { goto error; } } if (server->hostname == NULL || server->port == 0 || server->name == NULL || server->version == NULL || server->desc == NULL) { LOG(ERROR, "Incomplete data from metaserver"); goto error; } if (!parse_metaserver_cert(server)) { /* Logging already done */ goto error; } SDL_LockMutex(server_head_mutex); DL_PREPEND(server_head, server); server_count++; SDL_UnlockMutex(server_head_mutex); return; error: metaserver_free(server); }
/** * Go through the freelists and free puddles with no used chunks. * * @return * Number of freed puddles. */ static size_t mempool_free_puddles (mempool_struct *pool) { size_t chunksize_real, nrof_arrays, i, j, freed; mempool_chunk_struct *last_free, *chunk; mempool_puddle_struct *puddle, *next_puddle; HARD_ASSERT(pool != NULL); if (pool->flags & MEMPOOL_BYPASS_POOLS) { return 0; } freed = 0; for (i = 0; i < MEMPOOL_NROF_FREELISTS; i++) { chunksize_real = sizeof(mempool_chunk_struct) + (pool->chunksize << i); nrof_arrays = pool->expand_size >> i; /* Free empty puddles and setup puddle-local freelists */ for (puddle = pool->puddlelist[i], pool->puddlelist[i] = NULL; puddle != NULL; puddle = next_puddle) { next_puddle = puddle->next; /* Count free chunks in puddle, and set up a local freelist */ puddle->first_free = puddle->last_free = NULL; puddle->nrof_free = 0; for (j = 0; j < nrof_arrays; j++) { chunk = (mempool_chunk_struct *) (((char *) puddle->first_chunk) + chunksize_real * j); /* Find free chunks. */ if (CHUNK_FREE(MEM_USERDATA(chunk))) { if (puddle->nrof_free == 0) { puddle->first_free = chunk; puddle->last_free = chunk; chunk->next = NULL; } else { chunk->next = puddle->first_free; puddle->first_free = chunk; } puddle->nrof_free++; } } /* Can we actually free this puddle? */ if (puddle->nrof_free == nrof_arrays || (deiniting && pool == pool_puddle)) { /* Yup. Forget about it. */ efree(puddle->first_chunk); if (!deiniting || pool != pool_puddle) { mempool_return(pool_puddle, puddle); } pool->nrof_free[i] -= nrof_arrays; pool->nrof_allocated[i] -= nrof_arrays; freed++; } else { /* Nope, keep this puddle: put it back into the tracking list */ puddle->next = pool->puddlelist[i]; pool->puddlelist[i] = puddle; } } /* Sort the puddles by amount of free chunks. It will let us set up the * freelist so that the chunks from the fullest puddles are used first. * This should (hopefully) help us free some of the lesser-used puddles * earlier. */ pool->puddlelist[i] = sort_linked_list(pool->puddlelist[i], 0, sort_puddle_by_nrof_free, NULL, NULL, NULL); /* Finally: restore the global freelist */ pool->freelist[i] = &end_marker; last_free = &end_marker; for (puddle = pool->puddlelist[i]; puddle != NULL; puddle = puddle->next) { if (puddle->nrof_free > 0) { if (pool->freelist[i] == &end_marker) { pool->freelist[i] = puddle->first_free; } else { last_free->next = puddle->first_free; } puddle->last_free->next = &end_marker; last_free = puddle->last_free; } } } return freed; }
/** * Parse the metaserver certificate information. * * @param server * Metaserver entry. * @return * True on success, false on failure. */ static bool parse_metaserver_cert (server_struct *server) { HARD_ASSERT(server != NULL); if (server->cert == NULL || server->cert_sig == NULL) { /* No certificate. */ return true; } /* Generate a SHA512 hash of the certificate's contents. */ unsigned char cert_digest[SHA512_DIGEST_LENGTH]; if (SHA512((unsigned char *) server->cert, strlen(server->cert), cert_digest) == NULL) { LOG(ERROR, "SHA512() failed: %s", ERR_error_string(ERR_get_error(), NULL)); return false; } char cert_hash[SHA512_DIGEST_LENGTH * 2 + 1]; SOFT_ASSERT_RC(string_tohex(VS(cert_digest), VS(cert_hash), false) == sizeof(cert_hash) - 1, false, "string_tohex failed"); string_tolower(cert_hash); /* Verify the signature. */ if (!curl_verify(CURL_PKEY_TRUST_ULTIMATE, cert_hash, strlen(cert_hash), server->cert_sig, server->cert_sig_len)) { LOG(ERROR, "Failed to verify signature"); return false; } server_cert_info_t *info = ecalloc(1, sizeof(*info)); char buf[MAX_BUF]; size_t pos = 0; bool in_info = false; while (string_get_word(server->cert, &pos, '\n', VS(buf), 0)) { char *cp = buf; string_skip_whitespace(cp); string_strip_newline(cp); if (*cp == '\0') { continue; } if (strcmp(cp, cert_begin_str) == 0) { in_info = true; continue; } else if (!in_info) { continue; } else if (strcmp(cp, cert_end_str) == 0) { break; } char *cps[2]; if (string_split(cp, cps, arraysize(cps), ':') != arraysize(cps)) { LOG(ERROR, "Parsing error"); continue; } string_tolower(cps[0]); string_skip_whitespace(cps[1]); const char *key = cps[0]; const char *value = cps[1]; char **content = NULL; if (strcmp(key, "name") == 0) { content = &info->name; } else if (strcmp(key, "hostname") == 0) { content = &info->hostname; } else if (strcmp(key, "ipv4 address") == 0) { content = &info->ipv4_address; } else if (strcmp(key, "ipv6 address") == 0) { content = &info->ipv6_address; } else if (strcmp(key, "public key") == 0) { content = &info->pubkey; } else if (strcmp(key, "port") == 0) { info->port = atoi(value); } else if (strcmp(key, "crypto port") == 0) { info->port_crypto = atoi(value); } else { LOG(DEVEL, "Unrecognized key: %s", key); continue; } if (content != NULL) { StringBuffer *sb = stringbuffer_new(); if (*content != NULL) { stringbuffer_append_string(sb, *content); stringbuffer_append_char(sb, '\n'); efree(*content); } stringbuffer_append_string(sb, value); *content = stringbuffer_finish(sb); } } /* Ensure we got the data we need. */ if (info->name == NULL || info->hostname == NULL || info->pubkey == NULL || info->port_crypto <= 0 || (info->ipv4_address == NULL) != (info->ipv6_address == NULL)) { LOG(ERROR, "Certificate is missing required data."); goto error; } /* Ensure certificate attributes match the advertised ones. */ if (strcmp(info->hostname, server->hostname) != 0) { LOG(ERROR, "Certificate hostname does not match advertised hostname."); goto error; } if (strcmp(info->name, server->name) != 0) { LOG(ERROR, "Certificate name does not match advertised name."); goto error; } if (info->port != server->port) { LOG(ERROR, "Certificate port does not match advertised port."); goto error; } if (info->port_crypto != server->port_crypto) { LOG(ERROR, "Certificate crypto port does not match advertised crypto port."); goto error; } server->cert_info = info; return true; error: metaserver_cert_free(info); return false; }
/** * Parse a single metaserver data node within a 'server' node. * * @param node * The data node. * @param server * Allocated server structure. * @return * True on success, false on failure. */ static bool parse_metaserver_data_node (xmlNodePtr node, server_struct *server) { HARD_ASSERT(node != NULL); HARD_ASSERT(server != NULL); xmlChar *content = xmlNodeGetContent(node); SOFT_ASSERT_LABEL(content != NULL && *content != '\0', error, "Parsing error"); if (XML_STR_EQUAL(node->name, "Hostname")) { SOFT_ASSERT_LABEL(server->hostname == NULL, error, "Parsing error"); server->hostname = estrdup((const char *) content); } else if (XML_STR_EQUAL(node->name, "Port")) { SOFT_ASSERT_LABEL(server->port == 0, error, "Parsing error"); server->port = atoi((const char *) content); } else if (XML_STR_EQUAL(node->name, "PortCrypto")) { SOFT_ASSERT_LABEL(server->port_crypto == -1, error, "Parsing error"); server->port_crypto = atoi((const char *) content); } else if (XML_STR_EQUAL(node->name, "Name")) { SOFT_ASSERT_LABEL(server->name == NULL, error, "Parsing error"); server->name = estrdup((const char *) content); } else if (XML_STR_EQUAL(node->name, "PlayersCount")) { SOFT_ASSERT_LABEL(server->player == 0, error, "Parsing error"); server->player = atoi((const char *) content); } else if (XML_STR_EQUAL(node->name, "Version")) { SOFT_ASSERT_LABEL(server->version == NULL, error, "Parsing error"); server->version = estrdup((const char *) content); } else if (XML_STR_EQUAL(node->name, "TextComment")) { SOFT_ASSERT_LABEL(server->desc == NULL, error, "Parsing error"); server->desc = estrdup((const char *) content); } else if (XML_STR_EQUAL(node->name, "CertificatePublicKey")) { SOFT_ASSERT_LABEL(server->cert_pubkey == NULL, error, "Parsing error"); server->cert_pubkey = estrdup((const char *) content); } else if (XML_STR_EQUAL(node->name, "Certificate")) { SOFT_ASSERT_LABEL(server->cert == NULL, error, "Parsing error"); server->cert = estrdup((const char *) content); } else if (XML_STR_EQUAL(node->name, "CertificateSignature")) { SOFT_ASSERT_LABEL(server->cert_sig == NULL, error, "Parsing error"); unsigned char *sig; size_t sig_len; if (!math_base64_decode((const char *) content, &sig, &sig_len)) { LOG(ERROR, "Error decoding BASE64 certificate signature"); goto error; } server->cert_sig = sig; server->cert_sig_len = sig_len; } else { LOG(DEVEL, "Unrecognized node: %s", (const char *) node->name); } bool ret = true; goto out; error: ret = false; out: if (content != NULL) { xmlFree(content); } return ret; }
/** * Parse data returned from HTTP metaserver and add it to the list of servers. * * @param body * The data to parse. * @param body_size * Length of the body. */ static void parse_metaserver_data (const char *body, size_t body_size) { HARD_ASSERT(body != NULL); xmlSchemaParserCtxtPtr parser_ctx = NULL; xmlSchemaPtr schema = NULL; xmlSchemaValidCtxtPtr valid_ctx = NULL; xmlDocPtr doc = xmlReadMemory(body, body_size, "noname.xml", NULL, 0); if (doc == NULL) { LOG(ERROR, "Failed to parse data from metaserver"); goto out; } parser_ctx = xmlSchemaNewParserCtxt("schemas/Atrinik-ADS-7.xsd"); if (parser_ctx == NULL) { LOG(ERROR, "Failed to create a schema parser context"); goto out; } schema = xmlSchemaParse(parser_ctx); if (schema == NULL) { LOG(ERROR, "Failed to parse schema file"); goto out; } valid_ctx = xmlSchemaNewValidCtxt(schema); if (valid_ctx == NULL) { LOG(ERROR, "Failed to create a validation context"); goto out; } xmlSetStructuredErrorFunc(NULL, NULL); xmlSetGenericErrorFunc(NULL, parse_metaserver_data_error); xmlThrDefSetStructuredErrorFunc(NULL, NULL); xmlThrDefSetGenericErrorFunc(NULL, parse_metaserver_data_error); if (xmlSchemaValidateDoc(valid_ctx, doc) != 0) { LOG(ERROR, "XML verification failed."); goto out; } xmlNodePtr root = xmlDocGetRootElement(doc); if (root == NULL || !XML_STR_EQUAL(root->name, "Servers")) { LOG(ERROR, "No servers element found in metaserver XML"); goto out; } xmlNodePtr last = NULL; for (xmlNodePtr node = root->children; node != NULL; node = node->next) { last = node; } for (xmlNodePtr node = last; node != NULL; node = node->prev) { if (!XML_STR_EQUAL(node->name, "Server")) { continue; } parse_metaserver_node(node); } out: if (doc != NULL) { xmlFreeDoc(doc); } if (parser_ctx != NULL) { xmlSchemaFreeParserCtxt(parser_ctx); } if (schema != NULL) { xmlSchemaFree(schema); } if (valid_ctx != NULL) { xmlSchemaFreeValidCtxt(valid_ctx); } }
/** * Actually performs updating for the specified network graph widget. * @param widget * The widget. * @param type * The network graph type. * @param traffic * The traffic type (tx/rx). * @param bytes * Bytes. */ static void widget_network_graph_update(widgetdata *widget, int type, int traffic, size_t bytes) { HARD_ASSERT(widget != NULL); if (!widget->show) { return; } network_graph_widget_t *network_graph = widget->subwidget; network_graph_data_t *data = &network_graph->data[type]; if (data->data == NULL || data->width != widget->w) { if (data->data == NULL) { data->ticks = LastTick; } data->data = ereallocz(data->data, sizeof(*data->data) * NETWORK_GRAPH_TRAFFIC_MAX * data->width, sizeof(*data->data) * NETWORK_GRAPH_TRAFFIC_MAX * widget->w); data->width = widget->w; } if (data->width == 0) { return; } if (LastTick - data->ticks > 1000) { data->pos++; data->ticks = LastTick; } if (data->pos == data->width) { data->pos--; bool recalc_max = false; for (int i = 0; i < NETWORK_GRAPH_TRAFFIC_MAX; i++) { if (data->data[i] >= data->max) { recalc_max = true; } } memmove(data->data, data->data + NETWORK_GRAPH_TRAFFIC_MAX, sizeof(*data->data) * (NETWORK_GRAPH_TRAFFIC_MAX * (data->width - 1))); if (recalc_max) { data->max = 0; } for (int i = 0; i < NETWORK_GRAPH_TRAFFIC_MAX; i++) { data->data[data->pos * NETWORK_GRAPH_TRAFFIC_MAX + i] = 0; if (recalc_max) { for (int x = 0; x < data->pos; x++) { size_t bytes2 = data->data[x * NETWORK_GRAPH_TRAFFIC_MAX + i]; if (bytes2 > data->max) { data->max = bytes2; } } } } } size_t *dst = &data->data[data->pos * NETWORK_GRAPH_TRAFFIC_MAX + traffic]; *dst += bytes; if (*dst > data->max) { data->max = *dst; } widget->redraw = 1; }
/** * Remove a sprite entry from the sprite cache. * * @param cache * Cache entry to remove. */ static void sprite_cache_remove (sprite_cache_t *cache) { HARD_ASSERT(cache != NULL); HASH_DEL(sprites_cache, cache); }
/** * Add a sprite cache entry to the sprite cache. * * @param cache * Cache entry to add. */ static void sprite_cache_add (sprite_cache_t *cache) { HARD_ASSERT(cache != NULL); HASH_ADD_KEYPTR(hh, sprites_cache, cache->name, strlen(cache->name), cache); }
/** * Draw the object, centering it. Animation offsets are taken into * account for perfect centering, even with different image sizes in * animation. * * @param surface * Surface to render on. * @param tmp * Object to show. * @param x * X position. * @param y * Y position. * @param w * Maximum width. * @param h * Maximum height. * @param fit * Whether to fit the object into the maximum width/height by * zooming it as necessary. */ void object_show_centered (SDL_Surface *surface, object *tmp, int x, int y, int w, int h, bool fit) { HARD_ASSERT(surface != NULL); HARD_ASSERT(tmp != NULL); if (FaceList[tmp->face].sprite == NULL) { return; } /* Will be used for coordinate calculations. */ uint16_t face = tmp->face; /* If the item is animated, try to use the first animation face for * coordinate calculations to prevent 'jumping' of the animation. */ if (tmp->animation_id > 0) { check_animation_status(tmp->animation_id); if (animations[tmp->animation_id].num_animations) { uint16_t face_id; face_id = animations[tmp->animation_id].frame * tmp->direction; if (FaceList[animations[tmp->animation_id].faces[face_id]].sprite) { face = animations[tmp->animation_id].faces[face_id]; } } } int border_left = FaceList[face].sprite->border_left; int border_up = FaceList[face].sprite->border_up; if (tmp->glow[0] != '\0') { border_left -= SPRITE_GLOW_SIZE * 2; border_up -= SPRITE_GLOW_SIZE * 2; } int xlen = FaceList[face].sprite->bitmap->w - border_left - FaceList[face].sprite->border_right; int ylen = FaceList[face].sprite->bitmap->h - border_up - FaceList[face].sprite->border_down; if (tmp->glow[0] != '\0') { xlen += SPRITE_GLOW_SIZE * 2; ylen += SPRITE_GLOW_SIZE * 2; } double zoom_x = 1.0, zoom_y = 1.0; if (fit) { int xlen2 = xlen, ylen2 = ylen; if (xlen2 != w) { double factor = (double) w / xlen2; xlen2 *= factor; ylen2 *= factor; } if (ylen2 != h) { double factor = (double) h / ylen2; xlen2 *= factor; ylen2 *= factor; } if (xlen2 != xlen) { zoom_x = ((double) xlen2 + 0.5) / xlen; xlen = xlen2; border_left *= zoom_x; } if (ylen2 != ylen) { zoom_y = ((double) ylen2 + 0.5) / ylen; ylen = ylen2; border_up *= zoom_y; } } SDL_Rect box; if (xlen > w) { box.w = w; int temp = (xlen - w) / 2; box.x = border_left + temp; border_left = 0; } else { box.w = xlen; box.x = border_left; border_left = (w - xlen) / 2; } if (ylen > h) { box.h = h; int temp = (ylen - h) / 2; box.y = border_up + temp; border_up = 0; } else { box.h = ylen; box.y = border_up; border_up = (h - ylen) / 2; } if (face != tmp->face) { int temp = border_left - box.x; box.x = 0; box.w = FaceList[tmp->face].sprite->bitmap->w * zoom_x; border_left = temp; temp = border_up - box.y + (FaceList[face].sprite->bitmap->h * zoom_y - FaceList[tmp->face].sprite->bitmap->h * zoom_y); box.y = 0; box.h = FaceList[tmp->face].sprite->bitmap->h * zoom_y; border_up = temp; if (border_left < 0) { box.x = -border_left; box.w = FaceList[tmp->face].sprite->bitmap->w * zoom_x + border_left; if (box.w > w) { box.w = w; } border_left = 0; } else { if (box.w + border_left > w) { box.w -= ((box.w + border_left) - w); } } if (border_up < 0) { box.y = -border_up; box.h = FaceList[tmp->face].sprite->bitmap->h * zoom_y + border_up; if (box.h > h) { box.h = h; } border_up = 0; } else { if (box.h + border_up > h) { box.h -= ((box.h + border_up) - h); } } } sprite_effects_t effects; memset(&effects, 0, sizeof(effects)); snprintf(VS(effects.glow), "%s", tmp->glow); effects.glow_speed = tmp->glow_speed; effects.glow_state = tmp->glow_state; effects.zoom_x = zoom_x * 100.0; effects.zoom_y = zoom_y * 100.0; if (effects.glow[0] != '\0') { BIT_SET(effects.flags, SPRITE_FLAG_DARK); effects.dark_level = 0; } surface_show_effects(surface, x + border_left, y + border_up, &box, FaceList[tmp->face].sprite->bitmap, &effects); }