Improve type and length safety of commands taking binary data

pull/78/head
Jonathan G Rennison 5 years ago
parent 42b7e1f70b
commit b0284c8d9e

@ -260,7 +260,7 @@ CommandProc CmdRenamePlan;
CommandProc CmdDesyncCheck;
#define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type}
#define DEF_CMD(proc, flags, type) Command(proc, #proc, (CommandFlags)flags, type)
/**
* The master command table
@ -638,7 +638,7 @@ static int _docommand_recursive = 0;
*/
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
{
return DoCommand(container->tile, container->p1, container->p2, flags, container->cmd & CMD_ID_MASK, container->text.c_str());
return DoCommand(container->tile, container->p1, container->p2, flags, container->cmd & CMD_ID_MASK, container->text.c_str(), container->binary_length);
}
/*!
@ -651,10 +651,11 @@ CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
* @param flags Flags for the command and how to execute the command
* @param cmd The command-id to execute (a value of the CMD_* enums)
* @param text The text to pass
* @param binary_length The length of binary data in text
* @see CommandProc
* @return the cost
*/
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text)
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text, uint32 binary_length)
{
SCOPE_INFO_FMT([=], "DoCommand: tile: %X (%d x %d), p1: 0x%X, p2: 0x%X, flags: 0x%X, company: %s, cmd: 0x%X (%s)",
tile, TileX(tile), TileY(tile), p1, p2, flags, scope_dumper().CompanyInfo(_current_company), cmd, GetCommandName(cmd));
@ -665,7 +666,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags,
if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR;
/* Chop of any CMD_MSG or other flags; we don't need those here */
CommandProc *proc = _command_proc_table[cmd & CMD_ID_MASK].proc;
const Command &command = _command_proc_table[cmd & CMD_ID_MASK];
_docommand_recursive++;
@ -673,7 +674,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags,
if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) {
if (_docommand_recursive == 1) _cleared_object_areas.Clear();
SetTownRatingTestMode(true);
res = proc(tile, flags & ~DC_EXEC, p1, p2, text);
res = command.Execute(tile, flags & ~DC_EXEC, p1, p2, text, binary_length);
SetTownRatingTestMode(false);
if (res.Failed()) {
goto error;
@ -695,7 +696,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags,
/* Execute the command here. All cost-relevant functions set the expenses type
* themselves to the cost object at some point */
if (_docommand_recursive == 1) _cleared_object_areas.Clear();
res = proc(tile, flags, p1, p2, text);
res = command.Execute(tile, flags, p1, p2, text, binary_length);
if (res.Failed()) {
error:
_docommand_recursive--;
@ -732,7 +733,7 @@ Money GetAvailableMoneyForCommand()
*/
bool DoCommandP(const CommandContainer *container, bool my_cmd)
{
return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text.c_str(), my_cmd);
return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text.c_str(), my_cmd, container->binary_length);
}
/*!
@ -748,7 +749,7 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd)
* @param callback A callback function to call after the command is finished
* @param text The text to pass
* @param my_cmd indicator if the command is from a company or server (to display error messages for a user)
* @param binary_length The quantity of binary data in text
* @param binary_length The length of binary data in text
* @return \c true if the command succeeded, else \c false.
*/
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, uint32 binary_length)
@ -853,10 +854,10 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
byte cmd_id = cmd & CMD_ID_MASK;
assert(cmd_id < lengthof(_command_proc_table));
CommandProc *proc = _command_proc_table[cmd_id].proc;
const Command &command = _command_proc_table[cmd_id];
/* Shouldn't happen, but you never know when someone adds
* NULLs to the _command_proc_table. */
assert(proc != NULL);
assert(command.proc != NULL);
/* Command flags are used internally */
CommandFlags cmd_flags = GetCommandFlags(cmd);
@ -890,7 +891,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
_cleared_object_areas.Clear();
SetTownRatingTestMode(true);
BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE);
CommandCost res = proc(tile, flags, p1, p2, text);
CommandCost res = command.Execute(tile, flags, p1, p2, text, binary_length);
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE);
SetTownRatingTestMode(false);
@ -935,7 +936,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
* use the construction one */
_cleared_object_areas.Clear();
BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND);
CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text);
CommandCost res2 = command.Execute(tile, flags | DC_EXEC, p1, p2, text, binary_length);
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND);
if (cmd_id == CMD_COMPANY_CTRL) {

@ -34,7 +34,7 @@ static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID);
*/
#define return_cmd_error(errcode) return CommandCost(errcode);
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = NULL);
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = NULL, uint32 binary_length = 0);
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags);
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true, uint32 binary_length = 0);

@ -492,6 +492,7 @@ enum CommandFlags {
CMD_DEITY = 0x100, ///< the command may be executed by COMPANY_DEITY
CMD_STR_CTRL = 0x200, ///< the command's string may contain control strings
CMD_NO_EST = 0x400, ///< the command is never estimated.
CMD_PROCEX = 0x800, ///< the command proc function has extended parameters
};
DECLARE_ENUM_AS_BIT_SET(CommandFlags)
@ -537,6 +538,7 @@ enum CommandPauseLevel {
* @return The CommandCost of the command, which can be succeeded or failed.
*/
typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text);
typedef CommandCost CommandProcEx(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text, uint32 binary_length);
/**
* Define a command with the flags which belongs to it.
@ -545,10 +547,26 @@ typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1,
* the #CMD_AUTO, #CMD_OFFLINE and #CMD_SERVER values.
*/
struct Command {
CommandProc *proc; ///< The procedure to actually executing
union {
CommandProc *proc; ///< The procedure to actually execute
CommandProcEx *procex; ///< The procedure to actually execute, extended parameters
};
const char *name; ///< A human readable name for the procedure
CommandFlags flags; ///< The (command) flags to that apply to this command
CommandType type; ///< The type of command.
Command(CommandProc *proc, const char *name, CommandFlags flags, CommandType type)
: proc(proc), name(name), flags(flags & ~CMD_PROCEX), type(type) {}
Command(CommandProcEx *procex, const char *name, CommandFlags flags, CommandType type)
: procex(procex), name(name), flags(flags | CMD_PROCEX), type(type) {}
inline CommandCost Execute(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text, uint32 binary_length) const {
if (this->flags & CMD_PROCEX) {
return this->procex(tile, flags, p1, p2, text, binary_length);
} else {
return this->proc(tile, flags, p1, p2, text);
}
}
};
/**

Loading…
Cancel
Save