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; }
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; }