diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 9e82f672..29a53629 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -481,22 +481,19 @@ int BaseContext::LocalToString(cell_t local_addr, char **addr) return SP_ERROR_NONE; } -int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) +int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) { - cell_t *ph_addr; + char *ph_addr; int err; - unsigned int i, numcells = strlen(string); + unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t); - if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERROR_NONE) + if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE) { return err; } - for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) { @@ -523,19 +520,97 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *sour } len = strlen(source); - dest = (cell_t *)(ctx->memory + local_addr); + dest = (char *)(ctx->memory + local_addr); if ((size_t)len >= chars) { len = chars - 1; } - - for (i=0; i= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) + { + return SP_ERROR_INVALID_ADDRESS; + } + + len = strlen(source); + dest = (char *)(ctx->memory + local_addr); + + if ((size_t)len >= maxbytes) + { + len = maxbytes - 1; + needtocheck = true; + } + if (len <= 0) + { + return SP_ERROR_NONE; + } + + memcpy(dest, source, len); + if ((dest[len] & 1<<7) && needtocheck) + { + len -= __CheckValidChar(dest+len-1); } dest[len] = '\0'; + if (wrtnbytes) + { + *wrtnbytes = len; + } + return SP_ERROR_NONE; } diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 9fbe2dd6..56c7d14e 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -33,9 +33,10 @@ namespace SourcePawn virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); virtual int LocalToString(cell_t local_addr, char **addr); virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source); + virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes); virtual int PushCell(cell_t value); virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); - virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string); + virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string); virtual int PushCellsFromArray(cell_t array[], unsigned int numcells); virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite); virtual int BindNative(sp_nativeinfo_t *native); diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 61cbecfc..796a5a31 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -204,10 +204,8 @@ namespace SourcePawn */ virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; - /**:TODO: FIX ALL PACKED STUFF COMMENTS! + /** * Converts a local address to a physical string. - * Note that SourcePawn does not support packed strings, as such this function is - * 'cell to char' only. * * @param local_addr Local address in plugin. * @param addr Destination output pointer. @@ -216,7 +214,6 @@ namespace SourcePawn /** * Converts a physical string to a local address. - * Note that SourcePawn does not support packed strings. * * @param local_addr Local address in plugin. * @param chars Number of chars to write, including NULL terminator. @@ -224,6 +221,18 @@ namespace SourcePawn */ virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; + /** + * Converts a physical UTF-8 string to a local address. + * This function is the same as the ANSI version, except it will copy the maximum number of characters possible + * without accidentally chopping a multi-byte character. + * + * @param local_addr Local address in plugin. + * @param maxbytes Number of bytes to write, including NULL terminator. + * @param source Source string to copy. + * @param wrtnbytes Optionally filled with the number of written bytes. + */ + virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) =0; + /** * Pushes a cell onto the stack. Increases the parameter count by one. * @@ -253,7 +262,7 @@ namespace SourcePawn * @param phys_addr Optionally filled with physical address of new array. * @param string Source string to push. */ - virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0; + virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; /** * Individually pushes each cell of an array of cells onto the stack. Increases the