From 1e8db957bf0830a068b92a7c8dee023d46e518fe Mon Sep 17 00:00:00 2001 From: Mikusch Date: Wed, 27 Sep 2023 15:43:04 +0200 Subject: [PATCH] Add more functions to ArrayStack (#2019) * Add more functions to ArrayStack * Make formatting consistent with other functions * Don't remove the element for TopArray * Replace 4 with sizeof(cell_t) --- core/logic/smn_adt_stack.cpp | 97 +++++++++++++++++++++++++++++++++-- plugins/include/adt_stack.inc | 30 +++++++++++ 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/core/logic/smn_adt_stack.cpp b/core/logic/smn_adt_stack.cpp index 867963af..4b13baae 100644 --- a/core/logic/smn_adt_stack.cpp +++ b/core/logic/smn_adt_stack.cpp @@ -240,9 +240,9 @@ static cell_t PopStackCell(IPluginContext *pContext, const cell_t *params) } else { - if (idx >= array->blocksize() * 4) + if (idx >= array->blocksize() * sizeof(cell_t)) { - return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4); + return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t)); } *buffer = (cell_t)*((char *)blk + idx); } @@ -356,8 +356,8 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize()); rval = blk[idx]; } else { - if (idx >= array->blocksize() * 4) - return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4); + if (idx >= array->blocksize() * sizeof(cell_t)) + return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t)); rval = (cell_t)*((char *)blk + idx); } @@ -365,6 +365,32 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params) return rval; } +static cell_t ArrayStack_Top(IPluginContext *pContext, const cell_t *params) +{ + OpenHandle array(pContext, params[1], htCellStack); + if (!array.Ok()) + return 0; + + if (array->size() == 0) + return pContext->ThrowNativeError("stack is empty"); + + cell_t *blk = array->at(array->size() - 1); + size_t idx = (size_t)params[2]; + + cell_t rval; + if (params[3] == 0) { + if (idx >= array->blocksize()) + return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize()); + rval = blk[idx]; + } else { + if (idx >= array->blocksize() * sizeof(cell_t)) + return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t)); + rval = (cell_t)*((char *)blk + idx); + } + + return rval; +} + static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params) { OpenHandle array(pContext, params[1], htCellStack); @@ -387,6 +413,27 @@ static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *param return 1; } +static cell_t ArrayStack_TopString(IPluginContext *pContext, const cell_t *params) +{ + OpenHandle array(pContext, params[1], htCellStack); + if (!array.Ok()) + return 0; + + if (array->size() == 0) + return pContext->ThrowNativeError("stack is empty"); + + size_t idx = array->size() - 1; + cell_t *blk = array->at(idx); + + cell_t *pWritten; + pContext->LocalToPhysAddr(params[4], &pWritten); + + size_t numWritten; + pContext->StringToLocalUTF8(params[2], params[3], (char *)blk, &numWritten); + *pWritten = (cell_t)numWritten; + return 1; +} + static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params) { OpenHandle array(pContext, params[1], htCellStack); @@ -411,6 +458,29 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params return 0; } +static cell_t ArrayStack_TopArray(IPluginContext *pContext, const cell_t *params) +{ + OpenHandle array(pContext, params[1], htCellStack); + if (!array.Ok()) + return 0; + + if (array->size() == 0) + return pContext->ThrowNativeError("stack is empty"); + + cell_t *addr; + pContext->LocalToPhysAddr(params[2], &addr); + + size_t idx = array->size() - 1; + cell_t *blk = array->at(idx); + size_t indexes = array->blocksize(); + + if (params[3] != -1 && (size_t)params[3] <= array->blocksize()) + indexes = params[3]; + + memcpy(addr, blk, sizeof(cell_t) * indexes); + return 0; +} + static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params) { HandleError err; @@ -426,6 +496,21 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params) return array->blocksize(); } +static cell_t GetStackSize(IPluginContext *pContext, const cell_t *params) +{ + HandleError err; + CellArray *array; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + + if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + return array->size(); +} + REGISTER_NATIVES(cellStackNatives) { {"CreateStack", CreateStack}, @@ -444,13 +529,17 @@ REGISTER_NATIVES(cellStackNatives) {"ArrayStack.Clear", ClearStack}, {"ArrayStack.Clone", CloneStack}, {"ArrayStack.Pop", ArrayStack_Pop}, + {"ArrayStack.Top", ArrayStack_Top}, {"ArrayStack.PopString", ArrayStack_PopString}, + {"ArrayStack.TopString", ArrayStack_TopString}, {"ArrayStack.PopArray", ArrayStack_PopArray}, + {"ArrayStack.TopArray", ArrayStack_TopArray}, {"ArrayStack.Push", PushStackCell}, {"ArrayStack.PushString", PushStackString}, {"ArrayStack.PushArray", PushStackArray}, {"ArrayStack.Empty.get", IsStackEmpty}, {"ArrayStack.BlockSize.get", GetStackBlockSize}, + {"ArrayStack.Length.get", GetStackSize}, {NULL, NULL}, }; diff --git a/plugins/include/adt_stack.inc b/plugins/include/adt_stack.inc index 7607188d..a4bf8c83 100644 --- a/plugins/include/adt_stack.inc +++ b/plugins/include/adt_stack.inc @@ -99,6 +99,15 @@ methodmap ArrayStack < Handle // @error The stack is empty. public native any Pop(int block=0, bool asChar=false); + // Reads a cell value from a stack without removing it. + // + // @param block Optionally specify which block to read from + // (useful if the blocksize > 0). + // @param asChar Optionally read as a byte instead of a cell. + // @return Value read from the stack. + // @error The stack is empty. + public native any Top(int block=0, bool asChar=false); + // Pops a string value from a stack. // // @param buffer Buffer to store string. @@ -108,6 +117,15 @@ methodmap ArrayStack < Handle // @error The stack is empty. public native void PopString(char[] buffer, int maxlength, int &written = 0); + // Reads a string value from a stack without removing it. + // + // @param buffer Buffer to store string. + // @param maxlength Maximum size of the buffer. + // @param written Number of characters written to buffer, not including + // the null terminator. + // @error The stack is empty. + public native void TopString(char[] buffer, int maxlength, int &written = 0); + // Pops an array of cells from a stack. // // @param buffer Buffer to store the array in. @@ -116,6 +134,14 @@ methodmap ArrayStack < Handle // @error The stack is empty. public native void PopArray(any[] buffer, int size=-1); + // Reads an array of cells from a stack without removing it. + // + // @param buffer Buffer to store the array in. + // @param size If not set, assumes the buffer size is equal to the + // blocksize. Otherwise, the size passed is used. + // @error The stack is empty. + public native void TopArray(any[] buffer, int size=-1); + // Returns true if the stack is empty, false otherwise. property bool Empty { public native get(); @@ -125,6 +151,10 @@ methodmap ArrayStack < Handle property int BlockSize { public native get(); } + + property int Length { + public native get(); + } }; /**