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; }
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); } } }