Ejemplo n.º 1
0
int Proxy_final_verify(Proxy *conn)
{
  assert_mem(conn);
  assert_mem(conn->state);

  log(INFO, "Verifying final established crypto between peers.");

  check_err(conn->host.name, INVALID_HUB, "No name given for Hub after connect.");
  check_err(conn->client.name, INVALID_CLIENT, "No client name configured, how'd you do that?");
  check_err(biseq(conn->host.name, conn->state->them.name), PEER_VERIFY, "Expected Hub name and given Hub name do not match.");
  check_err(biseq(conn->client.name, conn->state->me.name), INVALID_CLIENT, "Final client name and given client name do not match.");
  check_err(biseq(conn->host.key, conn->host_given_key), PEER_VERIFY, "Expected and given Hub keys do not match.");

  bstring host_fp = CryptState_fingerprint_key(conn->state, CRYPT_THEIR_KEY, PK_PUBLIC);
  bstring client_pub_fp = CryptState_fingerprint_key(conn->state, CRYPT_MY_KEY, PK_PUBLIC);
  bstring client_pub = CryptState_export_key(conn->state, CRYPT_MY_KEY, PK_PUBLIC);

  bstring client_prv_fp = CryptState_fingerprint_key(conn->state, CRYPT_MY_KEY, PK_PRIVATE);
  bstring client_prv = CryptState_export_key(conn->state, CRYPT_MY_KEY, PK_PRIVATE);

  Node *host_info = Node_cons("[s[bsww", conn->state->them.name, conn->host_given_key, host_fp, "public", "their");
  check_err(host_info, STACKISH, "Failed to construct valid host name:key response.");

  Node *my_info = Node_cons("[s[bsw[bsww", conn->state->me.name, client_prv, client_prv_fp, "private", client_pub, client_pub_fp, "public", "my");
  check_err(my_info, STACKISH, "Failed to construct valid client name:key response.");

  check_err(Proxy_listener_send(conn, host_info, my_info), LISTENER_IO, "Failed to write initial connect response to listener.");

  log(INFO, "Peering cryptography validated.  Hub should be OK.");
  return 1;
  on_fail(Proxy_dump_invalid_state(conn); return 0);
}
Ejemplo n.º 2
0
// Retrieves a reference to a standardized bstring that represents the name
// of the data type.
//
// type_name - The name of the type.
// ret       - A pointer to where the standardized type name should be returned.
//
// Returns 0 if successful, otherwise returns -1.
int sky_property_get_standard_data_type_name(bstring type_name, bstring *ret)
{
    check(type_name != NULL, "Type name required");
    check(ret != NULL, "Return pointer required");

    // Check against standard types.
    if(biseq(&SKY_DATA_TYPE_INT, type_name)) {
        *ret = &SKY_DATA_TYPE_INT;
    }
    else if(biseq(&SKY_DATA_TYPE_FLOAT, type_name)) {
        *ret = &SKY_DATA_TYPE_FLOAT;
    }
    else if(biseq(&SKY_DATA_TYPE_BOOLEAN, type_name)) {
        *ret = &SKY_DATA_TYPE_BOOLEAN;
    }
    else if(biseq(&SKY_DATA_TYPE_STRING, type_name)) {
        *ret = &SKY_DATA_TYPE_STRING;
    }
    // If this is not a standard type then return the name that came in.
    else {
        sentinel("Type is not a standard type: %s", bdata(type_name));
    }

    return 0;

error:
    return -1;
}
Ejemplo n.º 3
0
static inline int same_handler(Handler *from, Handler *to)
{
    return biseq(from->send_ident, to->send_ident) && 
        biseq(from->recv_ident, to->recv_ident) &&
        biseq(from->recv_spec, to->recv_spec) &&
        biseq(from->send_spec, to->send_spec);
}
Ejemplo n.º 4
0
void ddbg_set(bstring object, bstring value)
{
    if (biseq(object, bfromcstr("vm_debug")))
    {
        vm->debug = (biseq(value, bfromcstr("on"))) ? true : false;
        printd(LEVEL_DEFAULT, "Debugging set to %d.\n", vm->debug);
    }
}
Ejemplo n.º 5
0
char *test_biseq() {
    bstring bstr_a = bfromcstr("a");
    bstring bstr_b = bfromcstr("a");
    int rc = biseq(bstr_a, bstr_b);
    mu_assert(rc == 1, "biseq a a failed");

    bassigncstr(bstr_b, "b");
    rc = biseq(bstr_a, bstr_b);
    mu_assert(rc == 0, "biseq a b failed");

    bdestroy(bstr_a);
    bdestroy(bstr_b);
    return NULL;
}
Ejemplo n.º 6
0
///
/// Adds a handler inside a scope, dealing with overridding
/// existing handlers.
///
void ppimpl_register(state_t* state, match_t* match)
{
    scope_t* scope;
    match_t* other;
    size_t a;

    if (list_size(&state->scopes) == 0)
    {
        // Global registration.
        list_append(&state->handlers, match);
        return;
    }
    scope = list_extract_at(&state->scopes, list_size(&state->scopes) - 1);

    // Check to see if this is already defined.
    for (a = 0; a < list_size(&state->handlers); a++)
    {
        other = list_get_at(&state->handlers, a);
        if (biseq(other->text.ref, match->text.ref))
        {
            // Collision; move the existing handler into
            // the scope's "old_handlers" list.
            list_append(&scope->old_handlers, other);
            list_extract_at(&state->handlers, a);
            a--;
        }
    }

    // Append to handlers and add the name to the scope's
    // new_handles so it can be cleared when the scope is
    // popped.
    list_append(&state->handlers, match);
    list_append(&scope->new_handlers, bstrcpy(match->text.ref));
}
Ejemplo n.º 7
0
Archivo: node.c Proyecto: dasfaha/sky
// Adds a dependency onto the list of dependencies.
//
// dependency   - The name of the dependency.
// dependencies - A pointer to an array of dependencies.
// count        - A pointer to where the number of dependencies is stored.
//
// Returns 0 if successful, otherwise returns -1.
int qip_ast_node_add_dependency(bstring dependency, bstring **dependencies, uint32_t *count)
{
    check(dependencies != NULL, "Dependency array pointer required");
    check(count != NULL, "Dependency count pointer required");
    
    // If dependency is blank or null or it is a built-in type then ignore it.
    if(dependency == NULL || biseqcstr(dependency, "") || qip_is_builtin_type_name(dependency)) {
        return 0;
    }
    
    // If dependency exists then exit.
    uint32_t i;
    for(i=0; i<*count; i++) {
        if(biseq(dependency, (*dependencies)[i])) {
            return 0;
        }
    }
    
    // Increment the count and append.
    (*count)++;
    *dependencies = realloc(*dependencies, sizeof(bstring) * (*count));
    check_mem(*dependencies);
    (*dependencies)[(*count)-1] = bstrcpy(dependency);
    check_mem((*dependencies)[(*count)-1]);
    
    return 0;

error:
    qip_ast_node_dependencies_free(dependencies, count);
    return -1;
}
Ejemplo n.º 8
0
// Deserializes an 'multi' message from a file stream.
//
// message - The message.
// file    - The file stream to read from.
//
// Returns 0 if successful, otherwise returns -1.
int sky_multi_message_unpack(sky_multi_message *message, FILE *file)
{
    int rc;
    size_t sz;
    bstring key = NULL;
    assert(message != NULL);
    assert(file != NULL);

    // Map
    uint32_t map_length = minipack_fread_map(file, &sz);
    check(sz > 0, "Unable to read map");

    // Map items
    uint32_t i;
    for(i=0; i<map_length; i++) {
        rc = sky_minipack_fread_bstring(file, &key);
        check(rc == 0, "Unable to read map key");

        if(biseq(key, &SKY_MULTI_KEY_COUNT_STR) == 1) {
            message->message_count = (uint32_t)minipack_fread_uint(file, &sz);
            check(sz != 0, "Unable to unpack count");
        }

        bdestroy(key);
    }

    return 0;

error:
    bdestroy(key);
    return -1;
}
Ejemplo n.º 9
0
int32_t ddbg_label_to_address(bstring label)
{
    unsigned int i;
    struct dbg_sym* sym;
    struct dbg_sym_payload_label* payload_label;

    if (symbols != NULL)
    {
        // Search through our debugging symbols.
        for (i = 0; i < list_size(symbols); i++)
        {
            sym = list_get_at(symbols, i);
            switch (sym->type)
            {
                case DBGFMT_SYMBOL_LABEL:
                    payload_label = (struct dbg_sym_payload_label*)sym->payload;
                    if (biseq(payload_label->label, label))
                    {
                        // The label matches, we have found our symbol entry.
                        printd(LEVEL_DEFAULT, "Label information: %s is at 0x%04X\n", payload_label->label->data, payload_label->address);
                        return payload_label->address;
                    }
                    break;
                default:
                    break;
            }
        }
    }

    // If we don't find a memory address, we return -1.
    return -1;
}
Ejemplo n.º 10
0
char *test_different_functions() {
  // create + length
  bstring string1 = bfromcstr("string");
  mu_assert_equal(6, blength(string1));

  // bassign, biseq
  bstring string2 = bfromcstr("foo");
  bassign(string2, string1);
  mu_assert(strcmp(bdata(string1), bdata(string2)) == 0, "both strings should be equal");
  mu_assert(biseq(string1, string2) == 1, "both strings should be equal");

  // bconcat
  bstring string2 = bfromcstr("foo");
  string1 = bfromcstr("Hello");
  string2 = bfromcstr(", World!");
  bconcat(string1, string2);
  mu_assert(strcmp("Hello, World!", bdata(string1)) == 0, "returned string not as expected");

  // bsplit
  string1 = bfromcstr("foo, bar, baz");
  struct bstrList *words;
  words = bsplit(string1, ',');
  mu_assert(strcmp("foo", bdata(words->entry[0])) == 0, "returned string not as expected");

  return NULL;
}
Ejemplo n.º 11
0
// Retrieves a message handler from the server by name.
//
// server - The server.
// name   - The name of the message handler.
// ret    - A pointer to where the handler should be returned.
//
// Returns 0 if successful, otherwise returns -1.
int sky_server_get_message_handler(sky_server *server, bstring name,
                                   sky_message_handler **ret)
{
    assert(server != NULL);
    assert(ret != NULL);
    check(blength(name), "Message name required");
    
    // Initialize return value.
    *ret = NULL;
    
    // Make sure a handler with the same name doesn't exist.
    uint32_t i;
    for(i=0; i<server->message_handler_count; i++) {
        if(biseq(server->message_handlers[i]->name, name) == 1) {
            *ret = server->message_handlers[i];
            break;
        }
    }

    return 0;

error:
    *ret = NULL;
    return -1;
}
Ejemplo n.º 12
0
// Deserializes an 'delete_table' message from a file stream.
//
// message - The message.
// file    - The file stream to read from.
//
// Returns 0 if successful, otherwise returns -1.
int sky_delete_table_message_unpack(sky_delete_table_message *message, FILE *file)
{
    int rc;
    size_t sz;
    bstring key = NULL;
    check(message != NULL, "Message required");
    check(file != NULL, "File stream required");

    // Map
    uint32_t map_length = minipack_fread_map(file, &sz);
    check(sz > 0, "Unable to read map");
    
    // Map items
    uint32_t i;
    for(i=0; i<map_length; i++) {
        rc = sky_minipack_fread_bstring(file, &key);
        check(rc == 0, "Unable to read map key");
        
        if(biseq(key, &SKY_DELETE_TABLE_MESSAGE_NAME_STR)) {
            rc = sky_minipack_fread_bstring(file, &message->name);
            check(rc == 0, "Unable to read table name");
        }

        bdestroy(key);
    }
    
    return 0;

error:
    bdestroy(key);
    return -1;
}
Ejemplo n.º 13
0
Archivo: block.c Proyecto: dasfaha/sky
// Searches for variable declarations within the block.
//
// node     - The node to search within.
// name     - The name of the variable to search for.
// var_decl - A pointer to where the variable declaration should be returned to.
//
// Returns 0 if successful, otherwise returns -1.
int qip_ast_block_get_var_decl(qip_ast_node *node, bstring name,
                               qip_ast_node **var_decl)
{
    unsigned int i;

    check(node != NULL, "Node required");
    check(node->type == QIP_AST_TYPE_BLOCK, "Node type must be 'block'");

    // Search expressions for variable declaration.
    *var_decl = NULL;
    for(i=0; i<node->block.expr_count; i++) {
        if(node->block.exprs[i]->type == QIP_AST_TYPE_VAR_DECL) {
            if(biseq(node->block.exprs[i]->var_decl.name, name)) {
                *var_decl = node->block.exprs[i];
                break;
            }
        }
    }

    return 0;
    
error:
    *var_decl = NULL;
    return -1;    
}
Ejemplo n.º 14
0
void ddbg_add_breakpoint(bstring file, int index)
{
    int32_t memory;

    if (!biseq(file, bfromcstr("memory")))
    {
        memory = ddbg_file_to_address(file, index);
    }
    else
    {
        if (index < 0)
        {
            printd(LEVEL_DEFAULT, "Memory address must be greater than 0.\n");
            memory = -1;
        }
        else
        {
            memory = index;
        }
    }

    // Did we get a valid result?
    if (memory == -1)
    {
        printd(LEVEL_DEFAULT, "Unable to resolve specified symbol.\n");
        return;
    }

    list_append(&breakpoints, breakpoint_create(memory, false, false));
    printd(LEVEL_DEFAULT, "Breakpoint added at 0x%04X.\n", memory);
}
Ejemplo n.º 15
0
END_TEST

START_TEST(core_011)
{
	struct tagbstring t = bsStatic("Hello world");
	unsigned char Ytstr[] = {
		0x72, 0x8f, 0x96, 0x96, 0x99, 0x4a,
		0xa1, 0x99, 0x9c, 0x96, 0x8e
	};
	bstring b, c;
	int ret = 0;
	b = bYEncode(&t);
	ck_assert(b != NULL);
	ck_assert_int_eq(ret, 0);
	ret = bisstemeqblk(b, Ytstr, 11);
	ck_assert_int_eq(ret, 1);
	c = bYDecode(b);
	ck_assert(c != NULL);
	ret = biseq(c, &t);
	ck_assert_int_eq(ret, 1);
	ret = bdestroy(b);
	ck_assert_int_eq(ret, BSTR_OK);
	ret = bdestroy(c);
	ck_assert_int_eq(ret, BSTR_OK);
}
Ejemplo n.º 16
0
int test13 (void) {
struct tagbstring t0 = bsStatic ("Random String");
struct vfgetc vctx;
bstring b;
int ret = 0;
int i;

	printf ("TEST: bSecureInput, bSecureDestroy.\n");

	for (i=0; i < 1000; i++) {
		unsigned char * h;

		vctx.ofs = 0;
		vctx.base = &t0;

		b = bSecureInput (INT_MAX, '\n', (bNgetc) test13_fgetc, &vctx);
		ret += 1 != biseq (b, &t0);
		h = b->data;
		bSecureDestroy (b);

		/* WARNING! Technically unsound code follows: */
		ret += (0 == memcmp (h, t0.data, t0.slen));

		if (ret) break;
	}

	printf ("\t# failures: %d\n", ret);

	return ret;
}
Ejemplo n.º 17
0
// Deserializes an 'lua::aggregate' message from a file stream.
//
// message - The message.
// file    - The file stream to read from.
//
// Returns 0 if successful, otherwise returns -1.
int sky_lua_aggregate_message_unpack(sky_lua_aggregate_message *message,
                                      FILE *file)
{
    int rc;
    size_t sz;
    bstring key = NULL;
    assert(message != NULL);
    assert(file != NULL);

    // Map
    uint32_t map_length = minipack_fread_map(file, &sz);
    check(sz > 0, "Unable to read map");
    
    // Map items
    uint32_t i;
    for(i=0; i<map_length; i++) {
        rc = sky_minipack_fread_bstring(file, &key);
        check(rc == 0, "Unable to read map key");
        
        if(biseq(key, &SKY_LUA_AGGREGATE_KEY_SOURCE) == 1) {
            rc = sky_minipack_fread_bstring(file, &message->source);
            check(rc == 0, "Unable to read source");
        }
        
        bdestroy(key);
        key = NULL;
    }

    return 0;

error:
    bdestroy(key);
    return -1;
}
Ejemplo n.º 18
0
void ddbg_attach(bstring hw)
{
    vm->host = host;
    if (biseq(hw, bfromcstr("lem1802")))
        vm_hw_lem1802_init(vm);
    else if (biseq(hw, bfromcstr("keyboard")))
        // TODO: keyboard
        vm_hw_lem1802_init(vm);
    else if (biseq(hw, bfromcstr("clock")))
        vm_hw_timer_init(vm);
    else if (biseq(hw, bfromcstr("m35fd")))
        vm_hw_m35fd_init(vm);
    else if (biseq(hw, bfromcstr("sped3")))
        vm_hw_sped3_init(vm);
    else
        printd(LEVEL_DEFAULT, "Unrecognized hardware.\n");
}
Ejemplo n.º 19
0
///
/// Finds a bin in the bin list by it's name.
///
int bin_seeker(const void* el, const void* indicator)
{
	if (el == NULL || indicator == NULL) return 0;
	if (biseq(((struct ldbin*)el)->name, (bstring)indicator))
		return 1;
	else
		return 0;
}
Ejemplo n.º 20
0
int Dir_serve_file(Dir *dir, Request *req, Connection *conn)
{
    FileRecord *file = NULL;
    bstring resp = NULL;
    bstring path = Request_path(req);
    bstring pattern = req->pattern;
    int rc = 0;
    int is_get = biseq(req->request_method, &HTTP_GET);
    int is_head = is_get ? 0 : biseq(req->request_method, &HTTP_HEAD);

    check(path, "Request had not path. That's weird.");
    req->response_size = 0;

    if(!(is_get || is_head)) {
        req->status_code = 405;
        rc = Response_send_status(conn, &HTTP_405);
        check_debug(rc == blength(&HTTP_405), "Failed to send 405 to client.");
        return -1;
    } else {
        file = Dir_resolve_file(dir, pattern, path);
        resp = Dir_calculate_response(req, file);

        if(resp) {
            rc = Response_send_status(conn, resp);
            check_debug(rc == blength(resp), "Failed to send error response on file serving.");
        } else if(is_get) {
            rc = Dir_stream_file(file, conn);
            req->response_size = rc;
            check_debug(rc == file->sb.st_size, "Didn't send all of the file, sent %d of %s.", rc, bdata(path));
        } else if(is_head) {
            rc = Dir_send_header(file, conn);
            check_debug(rc, "Failed to write header to socket.");
        } else {
            sentinel("How the hell did you get to here. Tell Zed.");
        }

        FileRecord_release(file);
        return 0;
    }

    sentinel("Invalid code branch, Tell Zed you have magic.");
error:
    FileRecord_release(file);
    return -1;
}
Ejemplo n.º 21
0
int lconv_entry_seeker(const void* e, const void* name)
{
	struct lconv_entry* el = (struct lconv_entry*)e;
	if (el->label == NULL) return 0;
	if (biseq(el->label, (bstring)name))
		return 1;
	else
		return 0;
}
Ejemplo n.º 22
0
///
/// Pops a scope from the stack.
///
void ppimpl_pop_scope(state_t* state)
{
    scope_t* scope;
    match_t* match;
    match_t* old;
    bstring name;
    size_t a, i;
    if (list_size(&state->scopes) == 0)
        return;
    scope = list_extract_at(&state->scopes, list_size(&state->scopes) - 1);

    // Delete text if this scope was silenced.
    if (!scope->active)
    {
        list_delete_range(&state->cached_output,
                scope->start_index,
                list_size(&state->cached_output) - 1);
    }

    // Delete handlers that were defined this scope.
    list_iterator_start(&scope->new_handlers);
    while (list_iterator_hasnext(&scope->new_handlers))
    {
        name = list_iterator_next(&scope->new_handlers);

        for (i = 0; i < list_size(&state->handlers); i++)
        {
            old = list_get_at(&state->handlers, i);
            if (biseq(name, old->text.ref))
            {
                // We need remove the old handler.
                // FIXME: Free the old handler.
                list_delete_at(&state->handlers, i);
                i--;
            }
        }

        bdestroy(name);
    }
    list_iterator_stop(&scope->new_handlers);
    list_destroy(&scope->new_handlers);

    // Restore handlers.
    for (a = 0; a < list_size(&scope->old_handlers); a++)
    {
        match = list_get_at(&scope->old_handlers, a);

        // Restore the old handler.
        list_append(&state->handlers, match);
        list_extract_at(&scope->old_handlers, a);
        a--;
    }
    list_destroy(&scope->old_handlers);

    // Free memory.
    free(scope);
}
Ejemplo n.º 23
0
bool hash_exists(hash *hashtable[], bstring key, unsigned int tablesize)
{
    hash *tmp = NULL;
    unsigned int thehash = makehash(key, tablesize);

    if (biseq(hashtable[thehash]->key, key) == 1)
    {
        return true;
    }
    else
    {
        /* traverse through the linked list (collision resolution) */
        for (tmp = hashtable[thehash]; tmp != NULL; tmp = tmp->next)
            if (biseq(tmp->key, key) == 1 && tmp->value != NULL)
                return true;
    }
    
    return false;
}
Ejemplo n.º 24
0
char *test_biseq(void)
{
	bstring b0 = bfromcstr(test);
	bstring b1 = bfromcstr(test);
	
	mu_assert(biseq(b0, b1) == 1, "Failed to equal test.");

	mu_assert(bdestroy(b0) == BSTR_OK, "Failed to bdestroy() afetr biseq().");
	b0 = bfromcstr(test_1);
	mu_assert(biseq(b0, b1) == 0, "Failed to not equal test.");

	mu_assert(bdestroy(b1) == BSTR_OK, "Failed to bdestroy() afetr biseq().");
	b1 = bfromcstr(test_1);
	mu_assert(biseq(b0, b1) == 1, "Failed to equal test.");
	
	mu_assert(bdestroy(b0) == BSTR_OK, "Failed to bdestroy() afetr biseq().");
	mu_assert(bdestroy(b1) == BSTR_OK, "Failed to bdestroy() afetr biseq().");
	return NULL;
}
Ejemplo n.º 25
0
char *test_bassigncstr() {
    bstring bstr = bfromcstr("");

    int rc = bassigncstr(bstr, "hello world");
    mu_assert(rc == BSTR_OK, "bassigncstr failed");

    bstring bstr2 = bfromcstr("hello world");
    mu_assert(biseq(bstr, bstr2) == 1, "bassigncstr not equal to bfromcstr");

    bdestroy(bstr2);
    bdestroy(bstr);
    return NULL;
}
Ejemplo n.º 26
0
char *test_bassign() {
    bstring b = bfromcstr("hello");

    bstring a = bfromcstr("a much longer string");
    int rc = bassign(a, b);

    mu_assert(rc == BSTR_OK, "bassign failed");
    mu_assert(blength(a) == blength(b), "bassign length diff");
    mu_assert(biseq(a, b) == 1, "bassign content diff");

    bdestroy(a);
    bdestroy(b);
    return NULL;
}
Ejemplo n.º 27
0
char *test_bassign()
{
	bstr = bfromcstr(test1);
	bstring try = NULL;
	bassign(try, bstr);
	bstring copy = bstrcpy(try);
	mu_assert(biseq(try, bstr), "Not equal after assignment.");
	mu_assert(biseq(copy, bstr), "Not equal after copy.");

	bdestroy(try);
	bdestroy(copy);
	bdestroy(bstr);
	return NULL;
}
Ejemplo n.º 28
0
const AffinityDomain*
affinity_getDomain(bstring domain)
{

    for ( int i=0; i < affinity_numberOfDomains; i++ )
    {
        if ( biseq(domain, domains[i].tag) )
        {
            return domains+i;
        }
    }

    return NULL;
}
Ejemplo n.º 29
0
inline bstring Dir_none_match(Request *req, FileRecord *file, int if_modified_since, bstring if_none_match)
{
    if(biseqcstr(if_none_match, "*") || biseq(if_none_match, file->etag)) {
        return &HTTP_304;
    } else {
        if(if_modified_since) {
            return Dir_if_modified_since(req, file, if_modified_since);
        } else {
            return NULL;
        }
    }

    return &HTTP_500;
}
Ejemplo n.º 30
0
Archivo: action.c Proyecto: fxstein/sky
// Deserializes an action from a file stream.
//
// action - The action.
// file   - The file stream to read from.
//
// Returns 0 if successful, otherwise returns -1.
int sky_action_unpack(sky_action *action, FILE *file)
{
    int rc;
    size_t sz;
    bstring key = NULL;
    check(action != NULL, "Message required");
    check(file != NULL, "File stream required");

    // Map
    uint32_t map_length = minipack_fread_map(file, &sz);
    check(sz > 0, "Unable to read map");
    
    // Map items
    uint32_t i;
    for(i=0; i<map_length; i++) {
        rc = sky_minipack_fread_bstring(file, &key);
        check(rc == 0, "Unable to read map key");
        
        if(biseq(key, &SKY_ACTION_ID_STR)) {
            action->id = (sky_action_id_t)minipack_fread_uint(file, &sz);
            check(sz > 0, "Unable to read action id");
        }
        else if(biseq(key, &SKY_ACTION_NAME_STR)) {
            rc = sky_minipack_fread_bstring(file, &action->name);
            check(rc == 0, "Unable to read action id");
        }

        bdestroy(key);
    }
    
    return 0;

error:
    bdestroy(key);
    return -1;
}