Update the way vectors are serialized to support mixed elements types

This commit is contained in:
Martín Capello 2023-01-17 14:22:35 -03:00 committed by David Capello
parent 8b547adfb7
commit 47a1c407c3
6 changed files with 49 additions and 10 deletions

View File

@ -1570,10 +1570,14 @@ static void ase_file_write_property_value(FILE* f,
case USER_DATA_PROPERTY_TYPE_VECTOR: {
auto& v = *std::get_if<UserData::Vector>(&value);
fputl(v.size(), f);
const uint16_t type = (v.empty() ? 0 : v.front().type());
const uint16_t type = doc::all_elements_of_same_type(v);
fputw(type, f);
for (const auto& elem : v) {
ASSERT(type == elem.type()); // Check that all elements have the same type
// Check that all elements have the same type when mode == 0. Or just that mode == 1
ASSERT(type != 0 && type == elem.type() || type == 0);
if (type == 0) {
fputw(elem.type(), f);
}
ase_file_write_property_value(f, elem);
}
break;

View File

@ -413,8 +413,6 @@ doc::UserData::Variant get_value_from_lua(lua_State* L, int index)
lua_pushnil(L);
while (lua_next(L, index) != 0) {
if (lua_isinteger(L, -2)) {
// TODO we should check that all values are of the same type
// to create the vector
if (++i != lua_tointeger(L, -2)) {
isArray = false;
lua_pop(L, 2); // Pop value and key
@ -509,7 +507,6 @@ doc::UserData::Vector get_value_from_lua(lua_State* L, int index)
--index;
lua_pushnil(L);
while (lua_next(L, index) != 0) {
// TODO we should check that all variants are of the same type
v.push_back(get_value_from_lua<doc::UserData::Variant>(L, -1));
lua_pop(L, 1);
}

View File

@ -1375,9 +1375,13 @@ const doc::UserData::Variant AsepriteDecoder::readPropertyValue(uint16_t type)
case USER_DATA_PROPERTY_TYPE_VECTOR: {
auto numElems = read32();
auto elemsType = read16();
auto elemType = elemsType;
std::vector<doc::UserData::Variant> value;
for (int k=0; k<numElems;++k) {
value.push_back(readPropertyValue(elemsType));
if (elemsType == 0) {
elemType = read16();
}
value.push_back(readPropertyValue(elemType));
}
return value;
}

View File

@ -149,6 +149,10 @@ namespace doc {
size_t count_nonempty_properties_maps(const UserData::PropertiesMaps& propertiesMaps);
// If all the vector elements are of the same type returns such type.
// Otherwise it returns -1.
int all_elements_of_same_type(const UserData::Vector& vector);
} // namespace doc
#endif

View File

@ -55,6 +55,17 @@ size_t count_nonempty_properties_maps(const UserData::PropertiesMaps& properties
return i;
}
int all_elements_of_same_type(const UserData::Vector& vector) {
int type = vector.empty() ? 0 : vector.front().type();
for (auto value : vector) {
if (type != value.type()) {
return 0;
}
}
return type;
}
void write_point(std::ostream& os, const gfx::Point& point)
{
write32(os, point.x);
@ -125,9 +136,8 @@ void write_property_value(std::ostream& os, const UserData::Variant& variant)
case USER_DATA_PROPERTY_TYPE_VECTOR: {
const std::vector<UserData::Variant>& vector = get_value<std::vector<UserData::Variant>>(variant);
write32(os, vector.size());
const uint16_t type = vector.size() == 0 ? 0 : vector.front().type();
write16(os, type);
for (auto elem : vector) {
write16(os, elem.type());
write_property_value(os, elem);
}
break;
@ -237,10 +247,10 @@ UserData::Variant read_property_value(std::istream& is, uint16_t type)
}
case USER_DATA_PROPERTY_TYPE_VECTOR: {
auto numElems = read32(is);
auto elemsType = read16(is);
std::vector<doc::UserData::Variant> value;
for (int k=0; k<numElems;++k) {
value.push_back(read_property_value(is, elemsType));
auto elemType = read16(is);
value.push_back(read_property_value(is, elemType));
}
return value;
}

View File

@ -130,3 +130,23 @@ do
assert(#spr.layers[2].properties("ext") == 1)
assert(spr.layers[2].properties("ext").b == 32)
end
-- Test save vector with different types inside
do
local spr = Sprite(32, 32)
spr.properties.a = { 3, "hi", {4, 5, 6}, {a="bye", b=10} }
spr:saveAs("_test_userdata_codec_3.aseprite")
spr:close()
spr = Sprite{ fromFile="_test_userdata_codec_3.aseprite" }
assert(#spr.properties.a == 4)
assert(spr.properties.a[1] == 3)
assert(spr.properties.a[2] == "hi")
assert(#spr.properties.a[3] == 3)
assert(spr.properties.a[3][1] == 4)
assert(spr.properties.a[3][2] == 5)
assert(spr.properties.a[3][3] == 6)
assert(spr.properties.a[4].a == "bye")
assert(spr.properties.a[4].b == 10)
end