Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/asset/intern/asset_indexer.cc
| Show First 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * \brief Single entry inside a #AssetIndexFile for reading. | * \brief Single entry inside a #AssetIndexFile for reading. | ||||
| */ | */ | ||||
| struct AssetEntryReader { | struct AssetEntryReader { | ||||
| private: | private: | ||||
| /** | /** | ||||
| * \brief Lookup table containing the elements of the entry. | * \brief Lookup table containing the elements of the entry. | ||||
| */ | */ | ||||
| ObjectValue::Lookup lookup; | DictionaryValue::Lookup lookup; | ||||
| StringRefNull get_name_with_idcode() const | StringRefNull get_name_with_idcode() const | ||||
| { | { | ||||
| return lookup.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value(); | return lookup.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value(); | ||||
| } | } | ||||
| public: | public: | ||||
| AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup()) | AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup()) | ||||
| { | { | ||||
| } | } | ||||
| ID_Type get_idcode() const | ID_Type get_idcode() const | ||||
| { | { | ||||
| const StringRefNull name_with_idcode = get_name_with_idcode(); | const StringRefNull name_with_idcode = get_name_with_idcode(); | ||||
| return GS(name_with_idcode.c_str()); | return GS(name_with_idcode.c_str()); | ||||
| } | } | ||||
| Show All 34 Lines | CatalogID get_catalog_id() const | ||||
| const std::string &catalog_id = | const std::string &catalog_id = | ||||
| lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value(); | lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value(); | ||||
| CatalogID catalog_uuid(catalog_id); | CatalogID catalog_uuid(catalog_id); | ||||
| return catalog_uuid; | return catalog_uuid; | ||||
| } | } | ||||
| void add_tags_to_meta_data(AssetMetaData *asset_data) const | void add_tags_to_meta_data(AssetMetaData *asset_data) const | ||||
| { | { | ||||
| const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS); | const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS); | ||||
| if (value_ptr == nullptr) { | if (value_ptr == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| const ArrayValue *array_value = (*value_ptr)->as_array_value(); | const ArrayValue *array_value = (*value_ptr)->as_array_value(); | ||||
| const ArrayValue::Items &elements = array_value->elements(); | const ArrayValue::Items &elements = array_value->elements(); | ||||
| for (const ArrayValue::Item &item : elements) { | for (const ArrayValue::Item &item : elements) { | ||||
| const StringRefNull tag_name = item->as_string_value()->value(); | const StringRefNull tag_name = item->as_string_value()->value(); | ||||
| BKE_asset_metadata_tag_add(asset_data, tag_name.c_str()); | BKE_asset_metadata_tag_add(asset_data, tag_name.c_str()); | ||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| struct AssetEntryWriter { | struct AssetEntryWriter { | ||||
| private: | private: | ||||
| ObjectValue::Items &attributes; | DictionaryValue::Items &attributes; | ||||
| public: | public: | ||||
| AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements()) | AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements()) | ||||
| { | { | ||||
| } | } | ||||
| /** | /** | ||||
| * \brief add id + name to the attributes. | * \brief add id + name to the attributes. | ||||
| * | * | ||||
| * NOTE: id and name are encoded like #ID.name | * NOTE: id and name are encoded like #ID.name | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | static void init_value_from_file_indexer_entry(AssetEntryWriter &result, | ||||
| if (!BLI_listbase_is_empty(&asset_data.tags)) { | if (!BLI_listbase_is_empty(&asset_data.tags)) { | ||||
| result.add_tags(&asset_data.tags); | result.add_tags(&asset_data.tags); | ||||
| } | } | ||||
| /* TODO: asset_data.IDProperties */ | /* TODO: asset_data.IDProperties */ | ||||
| } | } | ||||
| static void init_value_from_file_indexer_entries(ObjectValue &result, | static void init_value_from_file_indexer_entries(DictionaryValue &result, | ||||
| const FileIndexerEntries &indexer_entries) | const FileIndexerEntries &indexer_entries) | ||||
| { | { | ||||
| ArrayValue *entries = new ArrayValue(); | ArrayValue *entries = new ArrayValue(); | ||||
| ArrayValue::Items &items = entries->elements(); | ArrayValue::Items &items = entries->elements(); | ||||
| for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) { | for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) { | ||||
| const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link); | const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link); | ||||
| /* We also get non asset types (brushes, workspaces), when browsing using the asset browser. */ | /* We also get non asset types (brushes, workspaces), when browsing using the asset browser. */ | ||||
| if (indexer_entry->datablock_info.asset_data == nullptr) { | if (indexer_entry->datablock_info.asset_data == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ObjectValue *entry_value = new ObjectValue(); | DictionaryValue *entry_value = new DictionaryValue(); | ||||
| AssetEntryWriter entry(*entry_value); | AssetEntryWriter entry(*entry_value); | ||||
| init_value_from_file_indexer_entry(entry, indexer_entry); | init_value_from_file_indexer_entry(entry, indexer_entry); | ||||
| items.append_as(entry_value); | items.append_as(entry_value); | ||||
| } | } | ||||
| /* When no entries to index, we should not store the entries attribute as this would make the | /* When no entries to index, we should not store the entries attribute as this would make the | ||||
| * size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */ | * size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */ | ||||
| if (items.is_empty()) { | if (items.is_empty()) { | ||||
| delete entries; | delete entries; | ||||
| return; | return; | ||||
| } | } | ||||
| ObjectValue::Items &attributes = result.elements(); | DictionaryValue::Items &attributes = result.elements(); | ||||
| attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries)); | attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries)); | ||||
| } | } | ||||
| static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, | static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, | ||||
| const AssetEntryReader &entry) | const AssetEntryReader &entry) | ||||
| { | { | ||||
| indexer_entry.idcode = entry.get_idcode(); | indexer_entry.idcode = entry.get_idcode(); | ||||
| Show All 23 Lines | BLI_strncpy(asset_data->catalog_simple_name, | ||||
| sizeof(asset_data->catalog_simple_name)); | sizeof(asset_data->catalog_simple_name)); | ||||
| asset_data->catalog_id = entry.get_catalog_id(); | asset_data->catalog_id = entry.get_catalog_id(); | ||||
| entry.add_tags_to_meta_data(asset_data); | entry.add_tags_to_meta_data(asset_data); | ||||
| } | } | ||||
| static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, | static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, | ||||
| const ObjectValue &value) | const DictionaryValue &value) | ||||
| { | { | ||||
| const ObjectValue::Lookup attributes = value.create_lookup(); | const DictionaryValue::Lookup attributes = value.create_lookup(); | ||||
| const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES); | const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES); | ||||
| BLI_assert(entries_value != nullptr); | BLI_assert(entries_value != nullptr); | ||||
| if (entries_value == nullptr) { | if (entries_value == nullptr) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int num_entries_read = 0; | int num_entries_read = 0; | ||||
| const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements(); | const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements(); | ||||
| for (ArrayValue::Item element : elements) { | for (ArrayValue::Item element : elements) { | ||||
| const AssetEntryReader asset_entry(*element->as_object_value()); | const AssetEntryReader asset_entry(*element->as_dictionary_value()); | ||||
| FileIndexerEntry *entry = static_cast<FileIndexerEntry *>( | FileIndexerEntry *entry = static_cast<FileIndexerEntry *>( | ||||
| MEM_callocN(sizeof(FileIndexerEntry), __func__)); | MEM_callocN(sizeof(FileIndexerEntry), __func__)); | ||||
| init_indexer_entry_from_value(*entry, asset_entry); | init_indexer_entry_from_value(*entry, asset_entry); | ||||
| BLI_linklist_prepend(&indexer_entries.entries, entry); | BLI_linklist_prepend(&indexer_entries.entries, entry); | ||||
| num_entries_read += 1; | num_entries_read += 1; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | struct AssetIndex { | ||||
| /** | /** | ||||
| * Version number to use when version couldn't be read from an index file. | * Version number to use when version couldn't be read from an index file. | ||||
| */ | */ | ||||
| const int UNKNOWN_VERSION = -1; | const int UNKNOWN_VERSION = -1; | ||||
| /** | /** | ||||
| * `blender::io::serialize::Value` representing the contents of an index file. | * `blender::io::serialize::Value` representing the contents of an index file. | ||||
| * | * | ||||
| * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't | * Value is used over #DictionaryValue as the contents of the index could be corrupted and | ||||
| * represent an object. In case corrupted files are detected the `get_version` would return | * doesn't represent an object. In case corrupted files are detected the `get_version` would | ||||
| * `UNKNOWN_VERSION`. | * return `UNKNOWN_VERSION`. | ||||
| */ | */ | ||||
| std::unique_ptr<Value> contents; | std::unique_ptr<Value> contents; | ||||
| /** | /** | ||||
| * Constructor for when creating/updating an asset index file. | * Constructor for when creating/updating an asset index file. | ||||
| * #AssetIndex.contents are filled from the given \p indexer_entries. | * #AssetIndex.contents are filled from the given \p indexer_entries. | ||||
| */ | */ | ||||
| AssetIndex(const FileIndexerEntries &indexer_entries) | AssetIndex(const FileIndexerEntries &indexer_entries) | ||||
| { | { | ||||
| std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>(); | std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>(); | ||||
| ObjectValue::Items &root_attributes = root->elements(); | DictionaryValue::Items &root_attributes = root->elements(); | ||||
| root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION))); | root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION))); | ||||
| init_value_from_file_indexer_entries(*root, indexer_entries); | init_value_from_file_indexer_entries(*root, indexer_entries); | ||||
| contents = std::move(root); | contents = std::move(root); | ||||
| } | } | ||||
| /** | /** | ||||
| * Constructor when reading an asset index file. | * Constructor when reading an asset index file. | ||||
| * #AssetIndex.contents are read from the given \p value. | * #AssetIndex.contents are read from the given \p value. | ||||
| */ | */ | ||||
| AssetIndex(std::unique_ptr<Value> &value) : contents(std::move(value)) | AssetIndex(std::unique_ptr<Value> &value) : contents(std::move(value)) | ||||
| { | { | ||||
| } | } | ||||
| int get_version() const | int get_version() const | ||||
| { | { | ||||
| const ObjectValue *root = contents->as_object_value(); | const DictionaryValue *root = contents->as_dictionary_value(); | ||||
| if (root == nullptr) { | if (root == nullptr) { | ||||
| return UNKNOWN_VERSION; | return UNKNOWN_VERSION; | ||||
| } | } | ||||
| const ObjectValue::Lookup attributes = root->create_lookup(); | const DictionaryValue::Lookup attributes = root->create_lookup(); | ||||
| const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION); | const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION); | ||||
| if (version_value == nullptr) { | if (version_value == nullptr) { | ||||
| return UNKNOWN_VERSION; | return UNKNOWN_VERSION; | ||||
| } | } | ||||
| return (*version_value)->as_int_value()->value(); | return (*version_value)->as_int_value()->value(); | ||||
| } | } | ||||
| bool is_latest_version() const | bool is_latest_version() const | ||||
| { | { | ||||
| return get_version() == CURRENT_VERSION; | return get_version() == CURRENT_VERSION; | ||||
| } | } | ||||
| /** | /** | ||||
| * Extract the contents of this index into the given \p indexer_entries. | * Extract the contents of this index into the given \p indexer_entries. | ||||
| * | * | ||||
| * \return The number of entries read from the given entries. | * \return The number of entries read from the given entries. | ||||
| */ | */ | ||||
| int extract_into(FileIndexerEntries &indexer_entries) const | int extract_into(FileIndexerEntries &indexer_entries) const | ||||
| { | { | ||||
| const ObjectValue *root = contents->as_object_value(); | const DictionaryValue *root = contents->as_dictionary_value(); | ||||
| const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root); | const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root); | ||||
| return num_entries_read; | return num_entries_read; | ||||
| } | } | ||||
| }; | }; | ||||
| class AssetIndexFile : public AbstractFile { | class AssetIndexFile : public AbstractFile { | ||||
| public: | public: | ||||
| AssetLibraryIndex &library_index; | AssetLibraryIndex &library_index; | ||||
| ▲ Show 20 Lines • Show All 181 Lines • Show Last 20 Lines | |||||