Store one time each extension name in the external files chunk in .aseprite files

We've refactored the AsepriteExternalFiles struct to make it a
class (hiding members), storing maps ID -> filename per file
type (e.g. so we don't mix external tileset filenames with extensions
names, etc.), and re-using IDs for extensions names with the same
name (there is no need to store the same extension name multiple times
in the external files chunk).
This commit is contained in:
David Capello 2023-01-09 14:49:37 -03:00
parent 4232410719
commit dd33cef4be
3 changed files with 53 additions and 25 deletions

View File

@ -1278,16 +1278,19 @@ static void ase_file_write_external_files_chunk(
dio::AsepriteExternalFiles& ext_files,
const Sprite* sprite)
{
auto putExtentionIds = [](const UserData::PropertiesMaps& propertiesMaps, dio::AsepriteExternalFiles& ext_files) {
auto putExtentionIds = [](const UserData::PropertiesMaps& propertiesMaps,
dio::AsepriteExternalFiles& ext_files) {
for (auto propertiesMap : propertiesMaps) {
if (!propertiesMap.first.empty())
ext_files.put(propertiesMap.first, ASE_EXTERNAL_FILE_EXTENSION);
ext_files.insert(ASE_EXTERNAL_FILE_EXTENSION,
propertiesMap.first);
}
};
for (const Tileset* tileset : *sprite->tilesets()) {
if (!tileset->externalFilename().empty()) {
ext_files.put(tileset->externalFilename(), ASE_EXTERNAL_FILE_TILESET);
ext_files.insert(ASE_EXTERNAL_FILE_TILESET,
tileset->externalFilename());
}
putExtentionIds(tileset->userData().propertiesMaps(), ext_files);
@ -1334,13 +1337,13 @@ static void ase_file_write_external_files_chunk(
}
// No external files to write
if (ext_files.lastid == 0)
if (ext_files.items().empty())
return;
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_EXTERNAL_FILE);
fputl(ext_files.items.size(), f); // Number of entries
fputl(ext_files.items().size(), f); // Number of entries
ase_file_write_padding(f, 8);
for (const auto& it : ext_files.items) {
for (const auto& it : ext_files.items()) {
fputl(it.first, f); // ID
fputc(it.second.type, f); // Type
ase_file_write_padding(f, 7);
@ -1395,9 +1398,9 @@ static void ase_file_write_tileset_chunk(FILE* f, FileOp* fop,
// Flag 1 = external tileset
if (flags & ASE_TILESET_FLAG_EXTERNAL_FILE) {
auto it = ext_files.to_id.find(tileset->externalFilename());
if (it != ext_files.to_id.end()) {
auto file_id = it->second;
uint32_t file_id = 0;
if (ext_files.getIDByFilename(ASE_EXTERNAL_FILE_TILESET,
tileset->externalFilename(), file_id)) {
fputl(file_id, f);
fputl(tileset->externalTileset(), f);
}
@ -1532,7 +1535,8 @@ static void ase_file_write_properties_maps(FILE* f, FileOp* fop,
const std::string& extensionKey = propertiesMap.first;
uint32_t extensionId = 0;
if (!extensionKey.empty() &&
!ext_files.getIDByFilename(extensionKey, extensionId)) {
!ext_files.getIDByFilename(ASE_EXTERNAL_FILE_EXTENSION,
extensionKey, extensionId)) {
// This shouldn't ever happen, but if it does... most likely
// it is because we forgot to add the extensionID to the
// ext_files object. And this could happen if someone adds the

View File

@ -66,6 +66,7 @@
#define ASE_EXTERNAL_FILE_PALETTE 0
#define ASE_EXTERNAL_FILE_TILESET 1
#define ASE_EXTERNAL_FILE_EXTENSION 2
#define ASE_EXTERNAL_FILE_TYPES 3
namespace dio {
@ -105,44 +106,67 @@ struct AsepriteChunk {
int start;
};
struct AsepriteExternalFiles {
class AsepriteExternalFiles {
public:
struct Item {
std::string fn; // filename
uint8_t type; // type has one of the ASE_EXTERNAL_FILE_* values
};
std::map<uint32_t, Item> items;
std::map<std::string, uint32_t> to_id; // filename -> ID
uint32_t lastid = 0;
using Items = std::map<uint32_t, Item>;
const Items& items() const {
return m_items;
}
// Adds the external filename with the next autogenerated ID and specified type.
void put(const std::string& filename, uint8_t type) {
put(++lastid, filename, type);
uint32_t insert(const uint8_t type,
const std::string& filename) {
auto it = m_toID[type].find(filename);
if (it != m_toID[type].end())
return it->second;
else {
insert(++m_lastid, type, filename);
return m_lastid;
}
}
// Adds the external filename using the specified ID and type.
void put(uint32_t id, const std::string& filename, uint8_t type) {
items[id] = Item{ filename, type };
to_id[filename] = id;
void insert(uint32_t id,
const uint8_t type,
const std::string& filename) {
ASSERT(type >= 0 && type < ASE_EXTERNAL_FILE_TYPES);
m_items[id] = Item{ filename, type };
m_toID[type][filename] = id;
}
// Returns true if the given filename exists in the external files
// chunk, and assign its ID in "id"
bool getIDByFilename(const std::string& fn, uint32_t& id) const {
auto it = to_id.find(fn);
if (it == to_id.end())
bool getIDByFilename(const uint8_t type,
const std::string& fn,
uint32_t& id) const {
ASSERT(type >= 0 && type < ASE_EXTERNAL_FILE_TYPES);
auto it = m_toID[type].find(fn);
if (it == m_toID[type].end())
return false;
id = it->second;
return true;
}
bool getFilenameByID(uint32_t id, std::string& fn) const {
auto it = items.find(id);
if (it == items.end())
auto it = m_items.find(id);
if (it == m_items.end())
return false;
fn = it->second.fn;
return true;
}
private:
uint32_t m_lastid = 0; // ID used to add new items
Items m_items;
std::map<std::string, uint32_t> m_toID[ASE_EXTERNAL_FILE_TYPES];
};
} // namespace dio

View File

@ -1014,7 +1014,7 @@ void AsepriteDecoder::readExternalFiles(AsepriteExternalFiles& extFiles)
uint8_t type = read8();
readPadding(7);
std::string fn = readString();
extFiles.put(id, fn, type);
extFiles.insert(id, type, fn);
}
}