Beispiel #1
0
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
	uint16 op = argv[0].toUint16();

	// Use kString when accessing strings
	// This is possible, as strings inherit from arrays
	// and in this case (type 3) arrays are of type char *.
	// kString is almost exactly the same as kArray, so
	// this call is possible
	// TODO: we need to either merge SCI2 strings and
	// arrays together, and in the future merge them with
	// the SCI1 strings and arrays in the segment manager
	if (op == 0) {
		// New, check if the target type is 3 (string)
		if (argv[2].toUint16() == 3)
			return kString(s, argc, argv);
	} else {
		if (s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_STRING ||
			s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_SCRIPT) {
			return kString(s, argc, argv);
		}

#if 0
		if (op == 6) {
			if (s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_STRING ||
				s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_SCRIPT) {
				return kString(s, argc, argv);
			}
		}
#endif
	}

	switch (op) {
	case 0: { // New
		reg_t arrayHandle;
		SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle);
		array->setType(argv[2].toUint16());
		array->setSize(argv[1].toUint16());
		return arrayHandle;
	}
	case 1: { // Size
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return make_reg(0, array->getSize());
	}
	case 2: { // At (return value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return array->getValue(argv[2].toUint16());
	}
	case 3: { // Atput (put value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		uint32 index = argv[2].toUint16();
		uint32 count = argc - 3;

		if (index + count > 65535)
			break;

		if (array->getSize() < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[i + 3]);

		return argv[1]; // We also have to return the handle
	}
	case 4: // Free
		// Freeing of arrays is handled by the garbage collector
		return s->r_acc;
	case 5: { // Fill
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		uint16 index = argv[2].toUint16();

		// A count of -1 means fill the rest of the array
		uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16();
		uint16 arraySize = array->getSize();

		if (arraySize < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[4]);

		return argv[1];
	}
	case 6: { // Cpy
		if (argv[1].isNull() || argv[3].isNull()) {
			if (getSciVersion() == SCI_VERSION_3) {
				// FIXME: Happens in SCI3, probably because of a missing kernel function.
				warning("kArray(Cpy): Request to copy from or to a null pointer");
				return NULL_REG;
			} else {
				// SCI2-2.1: error out
				error("kArray(Cpy): Request to copy from or to a null pointer");
			}
		}

		reg_t arrayHandle = argv[1];
		SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]);
		//SciArray<reg_t> *array1 = !argv[1].isNull() ? s->_segMan->lookupArray(argv[1]) : s->_segMan->allocateArray(&arrayHandle);
		SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]);
		uint32 index1 = argv[2].toUint16();
		uint32 index2 = argv[4].toUint16();

		// The original engine ignores bad copies too
		if (index2 > array2->getSize())
			break;

		// A count of -1 means fill the rest of the array
		uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16();

		if (array1->getSize() < index1 + count)
			array1->setSize(index1 + count);

		for (uint16 i = 0; i < count; i++)
			array1->setValue(i + index1, array2->getValue(i + index2));

		return arrayHandle;
	}
	case 7: // Cmp
		// Not implemented in SSCI
		warning("kArray(Cmp) called");
		return s->r_acc;
	case 8: { // Dup
		if (argv[1].isNull()) {
			warning("kArray(Dup): Request to duplicate a null pointer");
#if 0
			// Allocate an array anyway
			reg_t arrayHandle;
			SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
			dupArray->setType(3);
			dupArray->setSize(0);
			return arrayHandle;
#endif
			return NULL_REG;
		}
		SegmentType sourceType = s->_segMan->getSegmentObj(argv[1].segment)->getType();
		if (sourceType == SEG_TYPE_SCRIPT) {
			// A technique used in later SCI2.1 and SCI3 games: the contents of a script
			// are loaded in an array (well, actually a string).
			Script *scr = s->_segMan->getScript(argv[1].segment);
			reg_t stringHandle;

			SciString *dupString = s->_segMan->allocateString(&stringHandle);
			dupString->setSize(scr->getBufSize());
			dupString->fromString(Common::String((const char *)scr->getBuf()));

			return stringHandle;
		} else if (sourceType != SEG_TYPE_ARRAY && sourceType != SEG_TYPE_SCRIPT) {
			error("kArray(Dup): Request to duplicate a segment which isn't an array or a script");
		}

		reg_t arrayHandle;
		SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
		// This must occur after allocateArray, as inserting a new object
		// in the heap object list might invalidate this pointer. Also refer
		// to the same issue in kClone()
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		dupArray->setType(array->getType());
		dupArray->setSize(array->getSize());

		for (uint32 i = 0; i < array->getSize(); i++)
			dupArray->setValue(i, array->getValue(i));

		return arrayHandle;
	}
	case 9: // Getdata
		if (!s->_segMan->isHeapObject(argv[1]))
			return argv[1];

		return readSelector(s->_segMan, argv[1], SELECTOR(data));
	default:
		error("Unknown kArray subop %d", op);
	}

	return NULL_REG;
}
Beispiel #2
0
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
	uint16 op = argv[0].toUint16();

	// Use kString when accessing strings
	// This is possible, as strings inherit from arrays
	// and in this case (type 3) arrays are of type char *.
	// kString is almost exactly the same as kArray, so
	// this call is possible
	// TODO: we need to either merge SCI2 strings and
	// arrays together, and in the future merge them with
	// the SCI1 strings and arrays in the segment manager
	if (op == 0) {
		// New, check if the target type is 3 (string)
		if (argv[2].toUint16() == 3)
			return kString(s, argc, argv);
	} else {
		if (s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_STRING ||
			s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_SCRIPT) {
			return kString(s, argc, argv);
		}

#if 0
		if (op == 6) {
			if (s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_STRING ||
				s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_SCRIPT) {
				return kString(s, argc, argv);
			}
		}
#endif
	}

	switch (op) {
	case 0: { // New
		reg_t arrayHandle;
		SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle);
		array->setType(argv[2].toUint16());
		array->setSize(argv[1].toUint16());
		return arrayHandle;
	}
	case 1: { // Size
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return make_reg(0, array->getSize());
	}
	case 2: { // At (return value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
			// HACK: Phantasmagoria 2 keeps trying to access past the end of an
			// array when it starts. I'm assuming it's trying to see where the
			// array ends, or tries to resize it. Adjust the array size
			// accordingly, and return NULL for now.
			if (array->getSize() == argv[2].toUint16()) {
				array->setSize(argv[2].toUint16());
				return NULL_REG;
			}
		}
		return array->getValue(argv[2].toUint16());
	}
	case 3: { // Atput (put value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		uint32 index = argv[2].toUint16();
		uint32 count = argc - 3;

		if (index + count > 65535)
			break;

		if (array->getSize() < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[i + 3]);

		return argv[1]; // We also have to return the handle
	}
	case 4: // Free
		// Freeing of arrays is handled by the garbage collector
		return s->r_acc;
	case 5: { // Fill
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		uint16 index = argv[2].toUint16();

		// A count of -1 means fill the rest of the array
		uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16();
		uint16 arraySize = array->getSize();

		if (arraySize < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[4]);

		return argv[1];
	}
	case 6: { // Cpy
		if (argv[1].isNull() || argv[3].isNull()) {
			if (getSciVersion() == SCI_VERSION_3) {
				// FIXME: Happens in SCI3, probably because of a missing kernel function.
				warning("kArray(Cpy): Request to copy from or to a null pointer");
				return NULL_REG;
			} else {
				// SCI2-2.1: error out
				error("kArray(Cpy): Request to copy from or to a null pointer");
			}
		}

		reg_t arrayHandle = argv[1];
		SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]);
		SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]);
		uint32 index1 = argv[2].toUint16();
		uint32 index2 = argv[4].toUint16();

		// The original engine ignores bad copies too
		if (index2 > array2->getSize())
			break;

		// A count of -1 means fill the rest of the array
		uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16();

		if (array1->getSize() < index1 + count)
			array1->setSize(index1 + count);

		for (uint16 i = 0; i < count; i++)
			array1->setValue(i + index1, array2->getValue(i + index2));

		return arrayHandle;
	}
	case 7: // Cmp
		// Not implemented in SSCI
		warning("kArray(Cmp) called");
		return s->r_acc;
	case 8: { // Dup
		if (argv[1].isNull()) {
			warning("kArray(Dup): Request to duplicate a null pointer");
#if 0
			// Allocate an array anyway
			reg_t arrayHandle;
			SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
			dupArray->setType(3);
			dupArray->setSize(0);
			return arrayHandle;
#endif
			return NULL_REG;
		}
		SegmentObj *sobj = s->_segMan->getSegmentObj(argv[1].getSegment());
		if (!sobj || sobj->getType() != SEG_TYPE_ARRAY)
			error("kArray(Dup): Request to duplicate a segment which isn't an array");

		reg_t arrayHandle;
		SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
		// This must occur after allocateArray, as inserting a new object
		// in the heap object list might invalidate this pointer. Also refer
		// to the same issue in kClone()
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		dupArray->setType(array->getType());
		dupArray->setSize(array->getSize());

		for (uint32 i = 0; i < array->getSize(); i++)
			dupArray->setValue(i, array->getValue(i));

		return arrayHandle;
	}
	case 9: // Getdata
		if (!s->_segMan->isHeapObject(argv[1]))
			return argv[1];

		return readSelector(s->_segMan, argv[1], SELECTOR(data));
	default:
		error("Unknown kArray subop %d", op);
	}

	return NULL_REG;
}