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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 /*
24 * This file is based on WME Lite.
25 * http://dead-code.org/redir.php?target=wmelite
26 * Copyright (c) 2011 Jan Nedoma
27 */
28
29 #include "engines/wintermute/base/base_scriptable.h"
30 #include "engines/wintermute/base/scriptables/script_stack.h"
31 #include "engines/wintermute/base/scriptables/script.h"
32 #include "engines/wintermute/base/scriptables/script_value.h"
33 #include "engines/wintermute/base/scriptables/script_ext_mem_buffer.h"
34 #include "common/file.h"
35
36 namespace Wintermute {
37
IMPLEMENT_PERSISTENT(SXMemBuffer,false)38 IMPLEMENT_PERSISTENT(SXMemBuffer, false)
39
40 BaseScriptable *makeSXMemBuffer(BaseGame *inGame, ScStack *stack) {
41 return new SXMemBuffer(inGame, stack);
42 }
43
44 //////////////////////////////////////////////////////////////////////////
SXMemBuffer(BaseGame * inGame,ScStack * stack)45 SXMemBuffer::SXMemBuffer(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) {
46 stack->correctParams(1);
47 _buffer = nullptr;
48 _size = 0;
49
50 int newSize = stack->pop()->getInt();
51 resize(MAX(0, newSize));
52 }
53
54 //////////////////////////////////////////////////////////////////////////
SXMemBuffer(BaseGame * inGame,void * buffer)55 SXMemBuffer::SXMemBuffer(BaseGame *inGame, void *buffer) : BaseScriptable(inGame) {
56 _size = 0;
57 _buffer = buffer;
58 }
59
60
61 //////////////////////////////////////////////////////////////////////////
~SXMemBuffer()62 SXMemBuffer::~SXMemBuffer() {
63 cleanup();
64 }
65
66 //////////////////////////////////////////////////////////////////////////
scToMemBuffer()67 void *SXMemBuffer::scToMemBuffer() {
68 return _buffer;
69 }
70
71 //////////////////////////////////////////////////////////////////////////
cleanup()72 void SXMemBuffer::cleanup() {
73 if (_size) {
74 free(_buffer);
75 }
76 _buffer = nullptr;
77 _size = 0;
78 }
79
80 //////////////////////////////////////////////////////////////////////////
resize(int newSize)81 bool SXMemBuffer::resize(int newSize) {
82 int oldSize = _size;
83
84 if (_size == 0) {
85 _buffer = malloc(newSize);
86 if (_buffer) {
87 _size = newSize;
88 }
89 } else {
90 void *newBuf = realloc(_buffer, newSize);
91 if (!newBuf) {
92 if (newSize == 0) {
93 _buffer = newBuf;
94 _size = newSize;
95 } else {
96 return STATUS_FAILED;
97 }
98 } else {
99 _buffer = newBuf;
100 _size = newSize;
101 }
102 }
103
104 if (_buffer && _size > oldSize) {
105 memset((byte *)_buffer + oldSize, 0, _size - oldSize);
106 }
107 return STATUS_OK;
108 }
109
110 //////////////////////////////////////////////////////////////////////////
checkBounds(ScScript * script,int start,int length)111 bool SXMemBuffer::checkBounds(ScScript *script, int start, int length) {
112 if (_buffer == nullptr) {
113 script->runtimeError("Cannot use Set/Get methods on an uninitialized memory buffer");
114 return false;
115 }
116 if (_size == 0) {
117 return true;
118 }
119
120 if (start < 0 || length == 0 || start + length > _size) {
121 script->runtimeError("Set/Get method call is out of bounds");
122 return false;
123 } else {
124 return true;
125 }
126 }
127
128 //////////////////////////////////////////////////////////////////////////
scToString()129 const char *SXMemBuffer::scToString() {
130 return "[membuffer object]";
131 }
132
133
134 //////////////////////////////////////////////////////////////////////////
scCallMethod(ScScript * script,ScStack * stack,ScStack * thisStack,const char * name)135 bool SXMemBuffer::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
136 //////////////////////////////////////////////////////////////////////////
137 // SetSize
138 //////////////////////////////////////////////////////////////////////////
139 if (strcmp(name, "SetSize") == 0) {
140 stack->correctParams(1);
141 int newSize = stack->pop()->getInt();
142 newSize = MAX(0, newSize);
143 if (DID_SUCCEED(resize(newSize))) {
144 stack->pushBool(true);
145 } else {
146 stack->pushBool(false);
147 }
148
149 return STATUS_OK;
150 }
151
152 //////////////////////////////////////////////////////////////////////////
153 // GetBool
154 //////////////////////////////////////////////////////////////////////////
155 else if (strcmp(name, "GetBool") == 0) {
156 stack->correctParams(1);
157 int start = stack->pop()->getInt();
158 if (!checkBounds(script, start, sizeof(bool))) {
159 stack->pushNULL();
160 } else {
161 stack->pushBool(*(bool *)((byte *)_buffer + start));
162 }
163
164 return STATUS_OK;
165 }
166
167 //////////////////////////////////////////////////////////////////////////
168 // GetByte
169 //////////////////////////////////////////////////////////////////////////
170 else if (strcmp(name, "GetByte") == 0) {
171 stack->correctParams(1);
172 int start = stack->pop()->getInt();
173 if (!checkBounds(script, start, sizeof(byte))) {
174 stack->pushNULL();
175 } else {
176 stack->pushInt(*(byte *)((byte *)_buffer + start));
177 }
178
179 return STATUS_OK;
180 }
181
182 //////////////////////////////////////////////////////////////////////////
183 // GetShort
184 //////////////////////////////////////////////////////////////////////////
185 else if (strcmp(name, "GetShort") == 0) {
186 stack->correctParams(1);
187 int start = stack->pop()->getInt();
188 if (!checkBounds(script, start, sizeof(short))) {
189 stack->pushNULL();
190 } else {
191 stack->pushInt(65536 + * (short *)((byte *)_buffer + start));
192 }
193
194 return STATUS_OK;
195 }
196
197 //////////////////////////////////////////////////////////////////////////
198 // GetInt / GetLong
199 //////////////////////////////////////////////////////////////////////////
200 else if (strcmp(name, "GetInt") == 0 || strcmp(name, "GetLong") == 0) {
201 stack->correctParams(1);
202 int start = stack->pop()->getInt();
203 if (!checkBounds(script, start, sizeof(int))) {
204 stack->pushNULL();
205 } else {
206 stack->pushInt(*(int *)((byte *)_buffer + start));
207 }
208
209 return STATUS_OK;
210 }
211
212 //////////////////////////////////////////////////////////////////////////
213 // GetFloat
214 //////////////////////////////////////////////////////////////////////////
215 else if (strcmp(name, "GetFloat") == 0) {
216 stack->correctParams(1);
217 int start = stack->pop()->getInt();
218 if (!checkBounds(script, start, sizeof(float))) {
219 stack->pushNULL();
220 } else {
221 stack->pushFloat(*(float *)((byte *)_buffer + start));
222 }
223
224 return STATUS_OK;
225 }
226
227 //////////////////////////////////////////////////////////////////////////
228 // GetDouble
229 //////////////////////////////////////////////////////////////////////////
230 else if (strcmp(name, "GetDouble") == 0) {
231 stack->correctParams(1);
232 int start = stack->pop()->getInt();
233 if (!checkBounds(script, start, sizeof(double))) {
234 stack->pushNULL();
235 } else {
236 stack->pushFloat(*(double *)((byte *)_buffer + start));
237 }
238
239 return STATUS_OK;
240 }
241
242 //////////////////////////////////////////////////////////////////////////
243 // GetString
244 //////////////////////////////////////////////////////////////////////////
245 else if (strcmp(name, "GetString") == 0) {
246 stack->correctParams(2);
247 int start = stack->pop()->getInt();
248 int length = stack->pop()->getInt();
249
250 // find end of string
251 if (length == 0 && start >= 0 && start < _size) {
252 for (int i = start; i < _size; i++) {
253 if (((char *)_buffer)[i] == '\0') {
254 length = i - start;
255 break;
256 }
257 }
258 }
259
260 if (!checkBounds(script, start, length)) {
261 stack->pushNULL();
262 } else {
263 char *str = new char[length + 1];
264 Common::strlcpy(str, (const char *)_buffer + start, length + 1);
265 stack->pushString(str);
266 delete[] str;
267 }
268 return STATUS_OK;
269 }
270
271 //////////////////////////////////////////////////////////////////////////
272 // GetPointer
273 //////////////////////////////////////////////////////////////////////////
274 else if (strcmp(name, "GetPointer") == 0) {
275 stack->correctParams(1);
276 int start = stack->pop()->getInt();
277 if (!checkBounds(script, start, sizeof(void *))) {
278 stack->pushNULL();
279 } else {
280 void *pointer = *(void **)((byte *)_buffer + start);
281 SXMemBuffer *buf = new SXMemBuffer(_gameRef, pointer);
282 stack->pushNative(buf, false);
283 }
284 return STATUS_OK;
285 }
286
287 //////////////////////////////////////////////////////////////////////////
288 // SetBool
289 //////////////////////////////////////////////////////////////////////////
290 else if (strcmp(name, "SetBool") == 0) {
291 stack->correctParams(2);
292 int start = stack->pop()->getInt();
293 bool val = stack->pop()->getBool();
294
295 if (!checkBounds(script, start, sizeof(bool))) {
296 stack->pushBool(false);
297 } else {
298 *(bool *)((byte *)_buffer + start) = val;
299 stack->pushBool(true);
300 }
301 return STATUS_OK;
302 }
303
304 //////////////////////////////////////////////////////////////////////////
305 // SetByte
306 //////////////////////////////////////////////////////////////////////////
307 else if (strcmp(name, "SetByte") == 0) {
308 stack->correctParams(2);
309 int start = stack->pop()->getInt();
310 byte val = (byte)stack->pop()->getInt();
311
312 if (!checkBounds(script, start, sizeof(byte))) {
313 stack->pushBool(false);
314 } else {
315 *(byte *)((byte *)_buffer + start) = val;
316 stack->pushBool(true);
317 }
318 return STATUS_OK;
319 }
320
321 //////////////////////////////////////////////////////////////////////////
322 // SetShort
323 //////////////////////////////////////////////////////////////////////////
324 else if (strcmp(name, "SetShort") == 0) {
325 stack->correctParams(2);
326 int start = stack->pop()->getInt();
327 short val = (short)stack->pop()->getInt();
328
329 if (!checkBounds(script, start, sizeof(short))) {
330 stack->pushBool(false);
331 } else {
332 *(short *)((byte *)_buffer + start) = val;
333 stack->pushBool(true);
334 }
335 return STATUS_OK;
336 }
337
338 //////////////////////////////////////////////////////////////////////////
339 // SetInt / SetLong
340 //////////////////////////////////////////////////////////////////////////
341 else if (strcmp(name, "SetInt") == 0 || strcmp(name, "SetLong") == 0) {
342 stack->correctParams(2);
343 int start = stack->pop()->getInt();
344 int val = stack->pop()->getInt();
345
346 if (!checkBounds(script, start, sizeof(int))) {
347 stack->pushBool(false);
348 } else {
349 *(int *)((byte *)_buffer + start) = val;
350 stack->pushBool(true);
351 }
352 return STATUS_OK;
353 }
354
355 //////////////////////////////////////////////////////////////////////////
356 // SetFloat
357 //////////////////////////////////////////////////////////////////////////
358 else if (strcmp(name, "SetFloat") == 0) {
359 stack->correctParams(2);
360 int start = stack->pop()->getInt();
361 float val = (float)stack->pop()->getFloat();
362
363 if (!checkBounds(script, start, sizeof(float))) {
364 stack->pushBool(false);
365 } else {
366 *(float *)((byte *)_buffer + start) = val;
367 stack->pushBool(true);
368 }
369 return STATUS_OK;
370 }
371
372 //////////////////////////////////////////////////////////////////////////
373 // SetDouble
374 //////////////////////////////////////////////////////////////////////////
375 else if (strcmp(name, "SetDouble") == 0) {
376 stack->correctParams(2);
377 int start = stack->pop()->getInt();
378 double val = stack->pop()->getFloat();
379
380 if (!checkBounds(script, start, sizeof(double))) {
381 stack->pushBool(false);
382 } else {
383 *(double *)((byte *)_buffer + start) = val;
384 stack->pushBool(true);
385 }
386 return STATUS_OK;
387 }
388
389 //////////////////////////////////////////////////////////////////////////
390 // SetString
391 //////////////////////////////////////////////////////////////////////////
392 else if (strcmp(name, "SetString") == 0) {
393 stack->correctParams(2);
394 int start = stack->pop()->getInt();
395 const char *val = stack->pop()->getString();
396
397 if (!checkBounds(script, start, strlen(val) + 1)) {
398 stack->pushBool(false);
399 } else {
400 memcpy((byte *)_buffer + start, val, strlen(val) + 1);
401 stack->pushBool(true);
402 }
403 return STATUS_OK;
404 }
405
406 //////////////////////////////////////////////////////////////////////////
407 // SetPointer
408 //////////////////////////////////////////////////////////////////////////
409 else if (strcmp(name, "SetPointer") == 0) {
410 stack->correctParams(2);
411 int start = stack->pop()->getInt();
412 /* ScValue *val = */ stack->pop();
413
414 if (!checkBounds(script, start, sizeof(void *))) {
415 stack->pushBool(false);
416 } else {
417 /*
418 int pointer = (int)Val->getMemBuffer();
419 memcpy((byte *)_buffer+Start, &Pointer, sizeof(void*));
420 stack->pushBool(true);
421 */
422 // TODO fix
423 stack->pushBool(false);
424
425 }
426 return STATUS_OK;
427 }
428
429 //////////////////////////////////////////////////////////////////////////
430 // DEBUG_Dump
431 //////////////////////////////////////////////////////////////////////////
432 else if (strcmp(name, "DEBUG_Dump") == 0) {
433 stack->correctParams(0);
434 if (_buffer && _size) {
435 warning("SXMemBuffer::ScCallMethod - DEBUG_Dump");
436 Common::DumpFile f;
437 f.open("buffer.bin");
438 f.write(_buffer, _size);
439 f.close();
440 }
441 stack->pushNULL();
442 return STATUS_OK;
443 } else {
444 return STATUS_FAILED;
445 }
446 }
447
448
449 //////////////////////////////////////////////////////////////////////////
scGetProperty(const Common::String & name)450 ScValue *SXMemBuffer::scGetProperty(const Common::String &name) {
451 _scValue->setNULL();
452
453 //////////////////////////////////////////////////////////////////////////
454 // Type (RO)
455 //////////////////////////////////////////////////////////////////////////
456 if (name == "Type") {
457 _scValue->setString("membuffer");
458 return _scValue;
459 }
460
461 //////////////////////////////////////////////////////////////////////////
462 // Size (RO)
463 //////////////////////////////////////////////////////////////////////////
464 if (name == "Size") {
465 _scValue->setInt(_size);
466 return _scValue;
467 } else {
468 return BaseScriptable::scGetProperty(name);
469 }
470 }
471
472
473 //////////////////////////////////////////////////////////////////////////
scSetProperty(const char * name,ScValue * value)474 bool SXMemBuffer::scSetProperty(const char *name, ScValue *value) {
475 /*
476 //////////////////////////////////////////////////////////////////////////
477 // Length
478 //////////////////////////////////////////////////////////////////////////
479 if (strcmp(name, "Length")==0) {
480 int origLength = _length;
481 _length = max(value->getInt(0), 0);
482
483 char propName[20];
484 if (_length < origLength) {
485 for(int i=_length; i < origLength; i++) {
486 sprintf(propName, "%d", i);
487 _values->DeleteProp(propName);
488 }
489 }
490 return STATUS_OK;
491 }
492 else*/ return BaseScriptable::scSetProperty(name, value);
493 }
494
495
496 //////////////////////////////////////////////////////////////////////////
persist(BasePersistenceManager * persistMgr)497 bool SXMemBuffer::persist(BasePersistenceManager *persistMgr) {
498
499 BaseScriptable::persist(persistMgr);
500
501 persistMgr->transferSint32(TMEMBER(_size));
502
503 if (persistMgr->getIsSaving()) {
504 if (_size > 0) {
505 persistMgr->putBytes((byte *)_buffer, _size);
506 }
507 } else {
508 if (_size > 0) {
509 _buffer = malloc(_size);
510 persistMgr->getBytes((byte *)_buffer, _size);
511 } else {
512 _buffer = nullptr;
513 }
514 }
515
516 return STATUS_OK;
517 }
518
519
520 //////////////////////////////////////////////////////////////////////////
scCompare(BaseScriptable * val)521 int SXMemBuffer::scCompare(BaseScriptable *val) {
522 if (_buffer == val->scToMemBuffer()) {
523 return 0;
524 } else {
525 return 1;
526 }
527 }
528
529 } // End of namespace Wintermute
530