ScummVM API documentation
runtime_script_value.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 //=============================================================================
23 //
24 // Runtime script value struct
25 //
26 //=============================================================================
27 
28 #ifndef AGS_ENGINE_SCRIPT_RUNTIME_SCRIPT_VALUE_H
29 #define AGS_ENGINE_SCRIPT_RUNTIME_SCRIPT_VALUE_H
30 
31 #include "ags/engine/ac/dynobj/cc_script_object.h"
32 #include "ags/engine/ac/dynobj/cc_static_array.h"
33 #include "ags/engine/script/script_api.h"
34 #include "ags/shared/util/memory.h"
35 
36 #include "ags/plugins/plugin_base.h"
37 
38 namespace AGS3 {
39 
40 enum ScriptValueType {
41  kScValUndefined, // to detect errors
42  kScValInteger, // as strictly 32-bit integer (for integer math)
43  kScValFloat, // as float (for floating point math), 32-bit
44  kScValPluginArg, // an 32-bit value, passed to a script function when called
45  // directly by plugin; is allowed to represent object pointer
46  kScValStackPtr, // as a pointer to stack entry
47  kScValData, // as a container for randomly sized data (usually array)
48  kScValGlobalVar, // as a pointer to script variable; used only for global vars,
49  // as pointer to local vars must have StackPtr type so that the
50  // stack allocation could work
51  kScValStringLiteral,// as a pointer to literal string (array of chars)
52  kScValStaticArray, // as a pointer to static global array (of static or dynamic objects)
53  kScValScriptObject, // as a pointer to managed script object
54  kScValPluginObject, // as a pointer to object managed by plugin (similar to
55  // kScValScriptObject, but has backward-compatible limitations)
56  kScValStaticFunction,// as a pointer to static function
57  kScValPluginFunction,// temporary workaround for plugins (unsafe function ptr)
58  kScValObjectFunction,// as a pointer to object member function, gets object pointer as
59  // first parameter
60  kScValCodePtr // as a pointer to element in byte-code array
61 };
62 
64 public:
66  Type = kScValUndefined;
67  IValue = 0;
68  Ptr = nullptr;
69  MgrPtr = nullptr;
70  Size = 0;
71  }
72 
73  RuntimeScriptValue(int32_t val) {
74  Type = kScValInteger;
75  IValue = val;
76  Ptr = nullptr;
77  MgrPtr = nullptr;
78  Size = 4;
79  }
80 
81  ScriptValueType Type;
82  Common::String methodName;
83  // The 32-bit value used for integer/float math and for storing
84  // variable/element offset relative to object (and array) address
85  union {
86  int32_t IValue; // access Value as int32 type
87  float FValue; // access Value as float type
88  };
89  // Pointer is used for storing... pointers - to objects, arrays,
90  // functions and stack entries (other RSV)
91  union {
92  void *Ptr; // generic data pointer
93  uint8_t *PtrU8; // byte buffer pointer
94  char *CStr; // char buffer pointer
95  RuntimeScriptValue *RValue;// access ptr as a pointer to Runtime Value
96  ScriptAPIFunction *SPfn; // access ptr as a pointer to Script API Static Function
97  ScriptAPIObjectFunction *ObjPfn; // access ptr as a pointer to Script API Object Function
98  };
99  // TODO: separation to Ptr and MgrPtr is only needed so far as there's
100  // a separation between Script*, Dynamic* and game entity classes.
101  // Once those classes are merged, it will no longer be needed.
102  union {
103  void *MgrPtr; // generic object manager pointer
104  IScriptObject *ObjMgr; // script object manager
105  CCStaticArray *ArrMgr; // static array manager
106  };
107  // The "real" size of data, either one stored in I/FValue,
108  // or the one referenced by Ptr. Used for calculating stack
109  // offsets.
110  // Original AGS scripts always assumed pointer is 32-bit.
111  // Therefore for stored pointers Size is always 4 both for x32
112  // and x64 builds, so that the script is interpreted correctly.
113  int Size;
114 
115  inline bool IsValid() const {
116  return Type != kScValUndefined;
117  }
118 
119  inline bool IsNull() const {
120  return Ptr == nullptr && IValue == 0;
121  }
122 
123  inline bool GetAsBool() const {
124  return !IsNull();
125  }
126 
127  inline void *GetPtrWithOffset() const {
128  return PtrU8 + IValue;
129  }
130 
131  inline void *GetRValuePtrWithOffset() const {
132  return static_cast<uint8_t *>(RValue->GetPtrWithOffset()) + this->IValue;
133  }
134 
135  inline RuntimeScriptValue &Invalidate() {
136  *this = RuntimeScriptValue();
137  return *this;
138  }
139 
140  inline RuntimeScriptValue &SetUInt8(uint8_t val) {
141  Type = kScValInteger;
142  methodName.clear();
143  IValue = val;
144  Ptr = nullptr;
145  MgrPtr = nullptr;
146  Size = 1;
147  return *this;
148  }
149 
150  inline RuntimeScriptValue &SetInt16(int16_t val) {
151  Type = kScValInteger;
152  methodName.clear();
153  IValue = val;
154  Ptr = nullptr;
155  MgrPtr = nullptr;
156  Size = 2;
157  return *this;
158  }
159 
160  inline RuntimeScriptValue &SetInt32(int32_t val) {
161  Type = kScValInteger;
162  methodName.clear();
163  IValue = val;
164  Ptr = nullptr;
165  MgrPtr = nullptr;
166  Size = 4;
167  return *this;
168  }
169 
170  inline RuntimeScriptValue &SetFloat(float val) {
171  Type = kScValFloat;
172  methodName.clear();
173  FValue = val;
174  Ptr = nullptr;
175  MgrPtr = nullptr;
176  Size = 4;
177  return *this;
178  }
179 
180  inline RuntimeScriptValue &SetInt32AsBool(bool val) {
181  return SetInt32(val ? 1 : 0);
182  }
183 
184  inline RuntimeScriptValue &SetFloatAsBool(bool val) {
185  return SetFloat(val ? 1.0F : 0.0F);
186  }
187 
188  inline RuntimeScriptValue &SetPluginArgument(int32_t val) {
189  Type = kScValPluginArg;
190  methodName.clear();
191  IValue = val;
192  Ptr = nullptr;
193  MgrPtr = nullptr;
194  Size = 4;
195  return *this;
196  }
197 
198  inline RuntimeScriptValue &SetStackPtr(RuntimeScriptValue *stack_entry) {
199  Type = kScValStackPtr;
200  methodName.clear();
201  IValue = 0;
202  RValue = stack_entry;
203  MgrPtr = nullptr;
204  Size = 4;
205  return *this;
206  }
207 
208  inline RuntimeScriptValue &SetData(void *data, int size) {
209  Type = kScValData;
210  methodName.clear();
211  IValue = 0;
212  Ptr = data;
213  MgrPtr = nullptr;
214  Size = size;
215  return *this;
216  }
217 
218  inline RuntimeScriptValue &SetGlobalVar(RuntimeScriptValue *glvar_value) {
219  Type = kScValGlobalVar;
220  methodName.clear();
221  IValue = 0;
222  RValue = glvar_value;
223  MgrPtr = nullptr;
224  Size = 4;
225  return *this;
226  }
227 
228  // TODO: size?
229  inline RuntimeScriptValue &SetStringLiteral(const char *str) {
230  Type = kScValStringLiteral;
231  methodName.clear();
232  IValue = 0;
233  Ptr = const_cast<char *>(str);
234  MgrPtr = nullptr;
235  Size = 4;
236  return *this;
237  }
238 
239  inline RuntimeScriptValue &SetStaticArray(void *object, CCStaticArray *manager) {
240  Type = kScValStaticArray;
241  methodName.clear();
242  IValue = 0;
243  Ptr = object;
244  ArrMgr = manager;
245  Size = 4;
246  return *this;
247  }
248 
249  inline RuntimeScriptValue &SetScriptObject(void *object, IScriptObject *manager) {
250  Type = kScValScriptObject;
251  methodName.clear();
252  IValue = 0;
253  Ptr = object;
254  ObjMgr = manager;
255  Size = 4;
256  return *this;
257  }
258 
259  inline RuntimeScriptValue &SetPluginObject(void *object, IScriptObject *manager) {
260  Type = kScValPluginObject;
261  methodName.clear();
262  IValue = 0;
263  Ptr = object;
264  ObjMgr = manager;
265  Size = 4;
266  return *this;
267  }
268 
269  inline RuntimeScriptValue &SetScriptObject(ScriptValueType type, void *object, IScriptObject *manager) {
270  Type = type;
271  IValue = 0;
272  Ptr = object;
273  ObjMgr = manager;
274  Size = 4;
275  return *this;
276  }
277 
278  inline RuntimeScriptValue &SetStaticFunction(ScriptAPIFunction *pfn) {
279  Type = kScValStaticFunction;
280  methodName.clear();
281  IValue = 0;
282  SPfn = pfn;
283  MgrPtr = nullptr;
284  Size = 4;
285  return *this;
286  }
287 
288  inline RuntimeScriptValue &SetPluginMethod(Plugins::ScriptContainer *sc, const Common::String &method) {
289  Type = kScValPluginFunction;
290  methodName = method;
291  Ptr = sc;
292  MgrPtr = nullptr;
293  IValue = 0;
294  Size = 4;
295  return *this;
296  }
297 
298  inline RuntimeScriptValue &SetObjectFunction(ScriptAPIObjectFunction *pfn) {
299  Type = kScValObjectFunction;
300  methodName.clear();
301  IValue = 0;
302  ObjPfn = pfn;
303  MgrPtr = nullptr;
304  Size = 4;
305  return *this;
306  }
307 
308  inline RuntimeScriptValue &SetCodePtr(void *ptr) {
309  Type = kScValCodePtr;
310  methodName.clear();
311  IValue = 0;
312  Ptr = ptr;
313  MgrPtr = nullptr;
314  Size = 4;
315  return *this;
316  }
317 
318  inline RuntimeScriptValue operator !() const {
319  return RuntimeScriptValue().SetInt32AsBool(!GetAsBool());
320  }
321 
322  inline bool operator ==(const RuntimeScriptValue &rval) const {
323  if (rval.Type == kScValPluginFunction) {
324  assert(!rval.methodName.empty());
325  return (Type == kScValPluginFunction) && (rval.methodName == methodName);
326  }
327 
328  return ((intptr_t)Ptr + (intptr_t)IValue) == ((intptr_t)rval.Ptr + (intptr_t)rval.IValue);
329  }
330  inline bool operator !=(const RuntimeScriptValue &rval) const {
331  return !(*this == rval);
332  }
333 
334  // FIXME: find out all certain cases when we are reading a pointer and store it
335  // as 32-bit value here. There should be a solution to distinct these cases and
336  // store value differently, otherwise it won't work for 64-bit build.
337  inline RuntimeScriptValue ReadValue() const {
338  switch (this->Type) {
339  case kScValStackPtr: {
340  // FIXME: join the kScValStackPtr with kScValData using some flag?
341  switch (RValue->Type) {
342  case kScValData:
343  // read from the stack memory buffer
344  return RuntimeScriptValue().SetInt32(*(int32_t *)(GetRValuePtrWithOffset()));
345  default:
346  // return the stack entry itself
347  return *RValue;
348  }
349  }
350  case kScValGlobalVar: {
351  // FIXME: join the kScValGlobalVar with kScValData using some flag?
352  switch (RValue->Type) {
353  case kScValData:
354  // read from the global memory buffer
355  return RuntimeScriptValue().SetInt32(AGS::Shared::Memory::ReadInt32LE(GetRValuePtrWithOffset()));
356  default:
357  // return the gvar entry itself
358  return *RValue;
359  }
360  }
361  case kScValStaticArray:
362  case kScValScriptObject:
363  return RuntimeScriptValue().SetInt32(this->ObjMgr->ReadInt32(this->Ptr, this->IValue));
364  default:
365  return RuntimeScriptValue().SetInt32(*(int32_t *)this->GetPtrWithOffset());
366  }
367  }
368 
369  // Notice, that there are only two valid cases when a pointer may be written:
370  // when the destination is a stack entry or global variable of free type
371  // (not kScValData type).
372  // In any other case, only the numeric value (integer/float) will be written.
373  inline void WriteValue(const RuntimeScriptValue &rval) {
374  switch (this->Type) {
375  case kScValStackPtr: {
376  // FIXME: join the kScValStackPtr with kScValData using some flag?
377  switch (RValue->Type) {
378  case kScValData:
379  // write into the stack memory buffer
380  *(int32_t *)(GetRValuePtrWithOffset()) = rval.IValue;
381  break;
382  default:
383  // write into the stack entry
384  *RValue = rval;
385  // On stack we assume each item has at least 4 bytes (with exception
386  // of arrays - kScValData). This is why we fixup the size in case
387  // the assigned value is less (char, int16).
388  RValue->Size = 4;
389  break;
390  }
391  break;
392  }
393  case kScValGlobalVar: {
394  // FIXME: join the kScValGlobalVar with kScValData using some flag?
395  switch (RValue->Type) {
396  case kScValData:
397  // write into the global memory buffer
398  AGS::Shared::Memory::WriteInt32LE(GetRValuePtrWithOffset(), rval.IValue);
399  break;
400  default:
401  // write into the gvar entry
402  *RValue = rval;
403  break;
404  }
405  break;
406  }
407  case kScValStaticArray:
408  case kScValScriptObject: {
409  this->ObjMgr->WriteInt32(this->Ptr, this->IValue, rval.IValue);
410  break;
411  }
412  default: {
413  *((int32_t *)this->GetPtrWithOffset()) = rval.IValue;
414  break;
415  }
416  }
417  }
418 
419  Plugins::PluginMethod pluginMethod() const {
420  return Plugins::PluginMethod((Plugins::PluginBase *)Ptr, methodName);
421  }
422 
423  // Helper functions for reading or writing values from/to
424  // object, referenced by this Runtime Value.
425  // Copy implementation depends on value type.
426  uint8_t ReadByte() const;
427  int16_t ReadInt16() const;
428  int32_t ReadInt32() const;
429  void WriteByte(uint8_t val);
430  void WriteInt16(int16_t val);
431  void WriteInt32(int32_t val);
432 
433  // Convert to most simple pointer type by resolving RValue ptrs and applying offsets;
434  // non pointer types are left unmodified
435  RuntimeScriptValue &DirectPtr();
436  // Similar to above, a slightly speed-optimised version for situations when we can
437  // tell for certain that we are expecting a pointer to the object and not its (first) field.
438  RuntimeScriptValue &DirectPtrObj();
439  // Resolve and return direct pointer to the referenced data; non pointer types return IValue
440  void *GetDirectPtr() const;
441 };
442 
443 } // namespace AGS3
444 
445 #endif
Definition: str.h:59
Definition: cc_script_object.h:60
Definition: runtime_script_value.h:63
Definition: cc_static_array.h:60
Definition: plugin_base.h:171
Definition: geometry.h:148
Definition: plugin_base.h:151
Definition: plugin_base.h:189
Definition: ags.h:40