int NativeInvoker::Invoke(cell_t *result)
{
	int err = SP_ERROR_NONE;

	if (pContext == NULL)
	{
		return SP_ERROR_INVALID_NATIVE;
	}

	if (m_errorstate != SP_ERROR_NONE)
	{
		err = m_errorstate;
		Cancel();
		return err;
	}

	cell_t tresult;

	if (result == NULL)
	{
		result = &tresult;
	}

	//This is for re-entrancy!
	IPluginContext *ctx = pContext;
	cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
	cell_t *temp_params = &_temp_params[1];
	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
	unsigned int numparams = m_curparam;
	unsigned int i;
	bool docopies = true;

	if (numparams)
	{
		//Save the info locally, then reset it for re-entrant calls.
		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
	}
	m_curparam = 0;
	pContext = NULL;

	/* Initialize 0th parameter */
	_temp_params[0] = numparams;

	/* Browse the parameters and build arrays */
	for (i = 0; i < numparams; i++)
	{
		/* Is this marked as an array? */
		if (temp_info[i].marked)
		{
			if (!temp_info[i].str.is_sz)
			{
				/* Allocate a normal/generic array */
				if ((err = ctx->HeapAlloc(temp_info[i].size, 
										  &temp_info[i].local_addr,
										  &temp_info[i].phys_addr))
					!= SP_ERROR_NONE)
				{
					break;
				}
				if (temp_info[i].orig_addr)
				{
					memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
				}
			}
			else
			{
				/* Calculate cells required for the string */
				size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);

				/* Allocate the buffer */
				if ((err = ctx->HeapAlloc(cells,
										  &temp_info[i].local_addr,
										  &temp_info[i].phys_addr))
					!= SP_ERROR_NONE)
				{
					break;
				}
				/* Copy original string if necessary */
				if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
				{
					/* Cut off UTF-8 properly */
					if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
					{
						if ((err = ctx->StringToLocalUTF8(temp_info[i].local_addr, 
														  temp_info[i].size, 
														  (const char *)temp_info[i].orig_addr,
														  NULL))
							!= SP_ERROR_NONE)
						{
							break;
						}
					}
					/* Copy a binary blob */
					else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
					{
						memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
					}
					/* Copy ASCII characters */
					else
					{
						if ((err = ctx->StringToLocal(temp_info[i].local_addr,
													  temp_info[i].size,
													  (const char *)temp_info[i].orig_addr))
							!= SP_ERROR_NONE)
						{
							break;
						}
					}
				}
			} /* End array/string calculation */
			/* Update the pushed parameter with the byref local address */
			temp_params[i] = temp_info[i].local_addr;
		}
		else
		{
			/* Just copy the value normally */
			temp_params[i] = m_params[i];
		}
	}

	/* Make the call if we can */
	if (err == SP_ERROR_NONE)
	{
		*result = native(ctx, _temp_params);
		if (ctx->GetLastNativeError() != SP_ERROR_NONE)
		{
			docopies = false;
			ctx->ClearLastNativeError();
		}
	}
	else
	{
		docopies = false;
	}

	/* i should be equal to the last valid parameter + 1 */
	while (i--)
	{
		if (!temp_info[i].marked)
		{
			continue;
		}

		if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
		{
			if (temp_info[i].orig_addr)
			{
				if (temp_info[i].str.is_sz)
				{
					memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);

				}
				else
				{
					if (temp_info[i].size == 1)
					{
						*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
					}
					else
					{
						memcpy(temp_info[i].orig_addr, 
							temp_info[i].phys_addr, 
							temp_info[i].size * sizeof(cell_t));
					}
				}
			}
		}

		if ((err = ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
		{
			return err;
		}
	}

	return err;
}
Exemple #2
0
void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results)
{
    if (!m_pVoteResults)
    {
        /* Call MenuAction_VoteEnd instead.  See if there are any extra winners. */
        unsigned int num_items = 1;
        for (unsigned int i=1; i<results->num_items; i++)
        {
            if (results->item_list[i].count != results->item_list[0].count)
            {
                break;
            }
            num_items++;
        }

        /* See if we need to pick a random winner. */
        unsigned int winning_item;
        if (num_items > 1)
        {
            /* Yes, we do. */
            srand(time(NULL));
            winning_item = rand() % num_items;
            winning_item = results->item_list[winning_item].item;
        } else {
            /* No, take the first. */
            winning_item = results->item_list[0].item;
        }

        unsigned int total_votes = results->num_votes;
        unsigned int winning_votes = results->item_list[0].count;

        DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
    } else {
        IPluginContext *pContext = m_pVoteResults->GetParentContext();
        bool no_call = false;
        int err;

        /* First array */
        cell_t client_array_address = -1;
        cell_t *client_array_base = NULL;
        cell_t client_array_size = results->num_clients + (results->num_clients * 2);
        if (client_array_size)
        {
            if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
                    != SP_ERROR_NONE)
            {
                logicore.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
                no_call = true;
            } else {
                cell_t target_offs = sizeof(cell_t) * results->num_clients;
                cell_t *cur_index = client_array_base;
                cell_t *cur_array;
                for (unsigned int i=0; i<results->num_clients; i++)
                {
                    /* Copy the array index */
                    *cur_index = target_offs;
                    /* Get the current array address */
                    cur_array = (cell_t *)((char *)cur_index + target_offs);
                    /* Store information */
                    cur_array[0] = results->client_list[i].client;
                    cur_array[1] = results->client_list[i].item;
                    /* Adjust for the new target by subtracting one indirection
                     * and adding one array.
                     */
                    target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
                    cur_index++;
                }
            }
        }

        /* Second array */
        cell_t item_array_address = -1;
        cell_t *item_array_base = NULL;
        cell_t item_array_size = results->num_items + (results->num_items * 2);
        if (item_array_size)
        {
            if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base))
                    != SP_ERROR_NONE)
            {
                logicore.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size);
                no_call = true;
            } else {
                cell_t target_offs = sizeof(cell_t) * results->num_items;
                cell_t *cur_index = item_array_base;
                cell_t *cur_array;
                for (unsigned int i=0; i<results->num_items; i++)
                {
                    /* Copy the array index */
                    *cur_index = target_offs;
                    /* Get the current array address */
                    cur_array = (cell_t *)((char *)cur_index + target_offs);
                    /* Store information */
                    cur_array[0] = results->item_list[i].item;
                    cur_array[1] = results->item_list[i].count;
                    /* Adjust for the new target by subtracting one indirection
                     * and adding one array.
                     */
                    target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
                    cur_index++;
                }
            }
        }

        /* Finally, push everything */
        if (!no_call)
        {
            m_pVoteResults->PushCell(menu->GetHandle());
            m_pVoteResults->PushCell(results->num_votes);
            m_pVoteResults->PushCell(results->num_clients);
            m_pVoteResults->PushCell(client_array_address);
            m_pVoteResults->PushCell(results->num_items);
            m_pVoteResults->PushCell(item_array_address);
            m_pVoteResults->Execute(NULL);
        }

        /* Free what we allocated, in reverse order as required */
        if (item_array_address != -1)
        {
            pContext->HeapPop(item_array_address);
        }
        if (client_array_address != -1)
        {
            pContext->HeapPop(client_array_address);
        }
    }
}