[Scummvm-git-logs] scummvm master -> 86cc6fe6274d81bbdbc9d94cbde50848722cdf1d
sev-
noreply at scummvm.org
Thu Jul 23 14:16:35 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
86cc6fe627 DIRECTOR: Fix saving members created at runtime
Commit: 86cc6fe6274d81bbdbc9d94cbde50848722cdf1d
https://github.com/scummvm/scummvm/commit/86cc6fe6274d81bbdbc9d94cbde50848722cdf1d
Author: Gianluca Boiano (morf3089 at gmail.com)
Date: 2026-07-23T16:16:31+02:00
Commit Message:
DIRECTOR: Fix saving members created at runtime
writeCast() skipped empty CAS* slots, collapsing the positional array:
a member duplicated to id 30 reloaded as id 6. Runtime-created members
also shared the child resources that are re-serialized from member
state (STXT, BITD, CLUT, SCVW), so editing a duplicate could overwrite
its source on save; clone those entries instead. Duplicated palettes
also copied struct memory as color data and shared the color array
with their source, double-freeing it on destruction.
Fixes duplicated members changing id and text on reload (verified with
duplicate/modify/save/reload on text_d5_win.dir; bitmap and palette
duplicates verified structurally)
Changed paths:
engines/director/archive-save.cpp
engines/director/cast.cpp
engines/director/castmember/palette.cpp
diff --git a/engines/director/archive-save.cpp b/engines/director/archive-save.cpp
index 07ec1a0ccf3..c77f9c974fc 100644
--- a/engines/director/archive-save.cpp
+++ b/engines/director/archive-save.cpp
@@ -334,10 +334,10 @@ bool RIFXArchive::writeCast(Common::SeekableWriteStream *writeStream, uint32 off
debugCN(5, kDebugSaving, "'CASt' indexes: [");
for (uint32 i = 0; i <= maxCastId; i++) {
uint32 castIndex = castIndexes.getValOrDefault(i, 0);
- if (castIndex) {
+ // CAS* is a positional array: empty slots are written as 0
+ writeStream->writeUint32BE(castIndex);
+ if (castIndex)
debugCN(5, kDebugSaving, (i == 0 ? "%d" : ", %d"), castIndex);
- writeStream->writeUint32BE(castIndex);
- }
}
debugC(5, kDebugSaving, "]");
@@ -381,21 +381,38 @@ Common::Array<Resource *> RIFXArchive::rebuildResources(Movie *movie) {
if (!res) {
// If the castId is new, create a new resource
// Assigning the next available index to the resource
- res = &castResMap[_resources.size()];
+ uint16 newResIndex = _resources.size();
+ res = &castResMap[newResIndex];
res->tag = MKTAG('C', 'A', 'S', 't');
res->accessed = true;
res->libResourceId = cast->_libResourceId;
- res->children = jt._value->_children;
- res->index = _resources.size();
+ res->index = newResIndex;
res->castId = jt._value->getID() - cast->_castArrayStart;
+ _resources.push_back(res);
+ // Clone the child resources that are re-serialized from
+ // their owning member's state: the duplicate must not
+ // share them with its source
+ res->children.clear();
for (auto child : jt._value->_children) {
+ if (child.tag == MKTAG('S', 'T', 'X', 'T') || child.tag == MKTAG('B', 'I', 'T', 'D') ||
+ child.tag == MKTAG('C', 'L', 'U', 'T') || child.tag == MKTAG('S', 'C', 'V', 'W')) {
+ uint16 childIndex = _resources.size();
+ Resource &newChild = _types[child.tag][childIndex];
+ newChild = child;
+ newChild.index = childIndex;
+ _resources.push_back(&newChild);
+ child.index = childIndex;
+ }
+ res->children.push_back(child);
+ }
+
+ for (auto child : res->children) {
_keyData[child.tag][res->index].push_back(child.index);
_keyTableUsedCount += 1;
_keyTableEntryCount += 1;
}
- _resources.push_back(res);
debugC(5, kDebugSaving, "RIFXArchive::rebuildResources(): new 'CASt' resource added");
} else {
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 597cf308c7b..666c348369d 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -274,6 +274,10 @@ bool Cast::duplicateCastMember(CastMember *source, CastMemberInfo *info, int tar
if (!source)
return true;
CastMember *target = source->duplicate(this, targetId);
+ // Some duplicate() implementations don't carry the child resource
+ // references; they only make sense within the same archive
+ if (target->_children.empty() && source->getCast() == this)
+ target->_children = source->_children;
if (info) {
CastMemberInfo *newInfo = new CastMemberInfo(*info);
diff --git a/engines/director/castmember/palette.cpp b/engines/director/castmember/palette.cpp
index 7534a8cb4ef..60d12236af1 100644
--- a/engines/director/castmember/palette.cpp
+++ b/engines/director/castmember/palette.cpp
@@ -42,7 +42,13 @@ PaletteCastMember::PaletteCastMember(Cast *cast, uint16 castId, PaletteCastMembe
source.load();
_loaded = true;
- _palette = source._palette ? new PaletteV4(*source._palette) : nullptr;
+ if (source._palette) {
+ byte *colors = new byte[source._palette->length * 3];
+ memcpy(colors, source._palette->palette, source._palette->length * 3);
+ _palette = new PaletteV4(source._palette->id, colors, source._palette->length);
+ } else {
+ _palette = nullptr;
+ }
}
PaletteCastMember::PaletteCastMember(Cast *cast, uint16 castId, byte *paletteData, PaletteV4 *pal)
@@ -52,12 +58,8 @@ PaletteCastMember::PaletteCastMember(Cast *cast, uint16 castId, byte *paletteDat
_loaded = true;
}
-// Need to make a deep copy
CastMember *PaletteCastMember::duplicate(Cast *cast, uint16 castId) {
- byte *buf = (byte *)malloc(_palette->length);
- memcpy(buf, _palette, _palette->length);
-
- return (CastMember *)(new PaletteCastMember(cast, castId, buf, _palette));
+ return new PaletteCastMember(cast, castId, *this);
}
PaletteCastMember::~PaletteCastMember() {
More information about the Scummvm-git-logs
mailing list