Blender V4.5
library.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <optional>
12
13#include "CLG_log.h"
14
15/* all types are needed here, in order to do memory operations */
16#include "DNA_ID.h"
17
18#include "BLI_utildefines.h"
19
20#include "BLI_ghash.h"
21#include "BLI_listbase.h"
22#include "BLI_path_utils.hh"
23#include "BLI_set.hh"
24#include "BLI_string.h"
25
26#include "BLT_translation.hh"
27
28#include "BLO_read_write.hh"
29
30#include "BKE_bpath.hh"
31#include "BKE_idtype.hh"
32#include "BKE_lib_id.hh"
33#include "BKE_lib_query.hh"
34#include "BKE_library.hh"
35#include "BKE_main.hh"
36#include "BKE_main_namemap.hh"
37#include "BKE_packedFile.hh"
38
39struct BlendDataReader;
40
41static CLG_LogRef LOG = {"bke.library"};
42
43using namespace blender::bke::library;
44
46{
47 BKE_main_namemap_destroy(&lib->runtime->name_map);
48}
49
50static void library_init_data(ID *id)
51{
52 Library *library = reinterpret_cast<Library *>(id);
53 library->runtime = MEM_new<LibraryRuntime>(__func__);
54}
55
56static void library_free_data(ID *id)
57{
58 Library *library = (Library *)id;
60 MEM_delete(library->runtime);
61 if (library->packedfile) {
62 BKE_packedfile_free(library->packedfile);
63 }
64}
65
66static void library_copy_data(Main *bmain,
67 std::optional<Library *> owner_library,
68 ID *id_dst,
69 const ID *id_src,
70 int /*flag*/)
71{
72 /* Libraries are always local IDs. */
73 BLI_assert(!owner_library || *owner_library == nullptr);
74 UNUSED_VARS_NDEBUG(bmain, owner_library);
75
76 const Library *library_src = reinterpret_cast<const Library *>(id_src);
77
78 /* Libraries are copyable now, but there should still be only one library ID for each linked
79 * blendfile (based on absolute filepath). */
80 BLI_assert(!bmain ||
81 !search_filepath_abs(&bmain->libraries, library_src->runtime->filepath_abs));
82
83 Library *library_dst = reinterpret_cast<Library *>(id_dst);
84 if (library_src->packedfile) {
85 library_dst->packedfile = BKE_packedfile_duplicate(library_src->packedfile);
86 }
87 library_dst->runtime = MEM_new<LibraryRuntime>(__func__, *library_src->runtime);
88 library_dst->runtime->filedata = nullptr;
89 library_dst->runtime->name_map = nullptr;
90}
91
97
98static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
99{
100 Library *lib = (Library *)id;
101
102 /* FIXME: Find if we should respect #BKE_BPATH_FOREACH_PATH_SKIP_PACKED here, and if not, explain
103 * why. */
104 if (lib->packedfile !=
105 nullptr /*&& (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0 */)
106 {
107 return;
108 }
109
110 if (BKE_bpath_foreach_path_fixed_process(bpath_data, lib->filepath, sizeof(lib->filepath))) {
111 BKE_library_filepath_set(bpath_data->bmain, lib, lib->filepath);
112 }
113}
114
115static void library_blend_write_data(BlendWriter *writer, ID *id, const void *id_address)
116{
117 Library *library = reinterpret_cast<Library *>(id);
118 const bool is_undo = BLO_write_is_undo(writer);
119
120 /* Clear runtime data. */
121 library->runtime = nullptr;
122
123 BLO_write_id_struct(writer, Library, id_address, id);
124 BKE_id_blend_write(writer, id);
125
126 /* Write packed file if necessary. */
127 if (library->packedfile) {
128 BKE_packedfile_blend_write(writer, library->packedfile);
129 if (!is_undo) {
130 CLOG_INFO(&LOG, 2, "Write packed .blend: %s", library->filepath);
131 }
132 }
133}
134
135static void library_blend_read_data(BlendDataReader * /*reader*/, ID *id)
136{
137 Library *lib = reinterpret_cast<Library *>(id);
138 lib->runtime = MEM_new<LibraryRuntime>(__func__);
139}
140
142 /*id_code*/ Library::id_type,
143 /*id_filter*/ FILTER_ID_LI,
144 /*dependencies_id_types*/ FILTER_ID_LI,
145 /*main_listbase_index*/ INDEX_ID_LI,
146 /*struct_size*/ sizeof(Library),
147 /*name*/ "Library",
148 /*name_plural*/ N_("libraries"),
149 /*translation_context*/ BLT_I18NCONTEXT_ID_LIBRARY,
151 /*asset_type_info*/ nullptr,
152
153 /*init_data*/ library_init_data,
154 /*copy_data*/ library_copy_data,
155 /*free_data*/ library_free_data,
156 /*make_local*/ nullptr,
157 /*foreach_id*/ library_foreach_id,
158 /*foreach_cache*/ nullptr,
159 /*foreach_path*/ library_foreach_path,
160 /*owner_pointer_get*/ nullptr,
161
162 /*blend_write*/ library_blend_write_data,
163 /*blend_read_data*/ library_blend_read_data,
164 /*blend_read_after_liblink*/ nullptr,
165
166 /*blend_read_undo_preserve*/ nullptr,
167
168 /*lib_override_apply_post*/ nullptr,
169};
170
171void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
172{
173 /* in some cases this is used to update the absolute path from the
174 * relative */
175 if (lib->filepath != filepath) {
176 STRNCPY(lib->filepath, filepath);
177 }
178
179 STRNCPY(lib->runtime->filepath_abs, filepath);
180
181 /* Not essential but set `filepath_abs` is an absolute copy of value which
182 * is more useful if its kept in sync. */
183 if (BLI_path_is_rel(lib->runtime->filepath_abs)) {
184 /* NOTE(@ideasman42): the file may be unsaved, in this case, setting the
185 * `filepath_abs` on an indirectly linked path is not allowed from the
186 * outliner, and its not really supported but allow from here for now
187 * since making local could cause this to be directly linked.
188 */
189 /* Never make paths relative to parent lib - reading code (blenloader) always set *all*
190 * `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */
191 const char *blendfile_path = BKE_main_blendfile_path(bmain);
192 BLI_path_abs(lib->runtime->filepath_abs, blendfile_path);
193 }
194}
195
197 blender::Set<Library *> &directly_used_libs,
198 Library *lib)
199{
200 BLI_assert(!directly_used_libs.contains(lib));
201
202 Library *best_parent_lib = nullptr;
203 bool do_break = false;
204 ListBase *lb;
205 ID *id_iter;
206 FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
207 FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id_iter) {
208 if (!ID_IS_LINKED(id_iter) || id_iter->lib != lib) {
209 continue;
210 }
211 MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
213 for (MainIDRelationsEntryItem *item = entry->from_ids; item; item = item->next) {
214 ID *from_id = item->id_pointer.from;
215 if (!ID_IS_LINKED(from_id)) {
217 continue;
218 }
219 Library *from_id_lib = from_id->lib;
220 if (from_id_lib == lib) {
221 continue;
222 }
223 if (directly_used_libs.contains(from_id_lib)) {
224 /* Found the first best possible candidate, no need to search further. */
225 BLI_assert(best_parent_lib == nullptr || best_parent_lib->runtime->temp_index > 0);
226 best_parent_lib = from_id_lib;
227 do_break = true;
228 break;
229 }
230 if (!from_id_lib->runtime->parent) {
231 rebuild_hierarchy_best_parent_find(bmain, directly_used_libs, from_id_lib);
232 }
233 if (!best_parent_lib ||
234 best_parent_lib->runtime->temp_index > from_id_lib->runtime->temp_index)
235 {
236 best_parent_lib = from_id_lib;
237 if (best_parent_lib->runtime->temp_index == 0) {
238 /* Found the first best possible candidate, no need to search further. */
239 BLI_assert(directly_used_libs.contains(best_parent_lib));
240 do_break = true;
241 break;
242 }
243 }
244 }
245 if (do_break) {
246 break;
247 }
248 }
250 if (do_break) {
251 break;
252 }
253 }
255
256 /* NOTE: It may happen that no parent library is found, e.g. if after deleting a directly used
257 * library, its indirect dependency is still around, but none of its linked IDs are used by local
258 * data. */
259 if (best_parent_lib) {
260 lib->runtime->parent = best_parent_lib;
261 lib->runtime->temp_index = best_parent_lib->runtime->temp_index + 1;
262 }
263 else {
264 lib->runtime->parent = nullptr;
265 lib->runtime->temp_index = 0;
266 directly_used_libs.add(lib);
267 }
268}
269
271{
273
274 /* Reset all values, they may have been set to irrelevant values by other processes (like the
275 * liboverride handling e.g., see #lib_override_libraries_index_define). */
276 LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
277 lib_iter->runtime->temp_index = 0;
278 }
279
280 /* Find all libraries with directly linked IDs (i.e. IDs used by local data). */
281 blender::Set<Library *> directly_used_libs;
282 ID *id_iter;
283 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
284 if (!ID_IS_LINKED(id_iter)) {
285 continue;
286 }
287 id_iter->lib->runtime->temp_index = 0;
288 if (directly_used_libs.contains(id_iter->lib)) {
289 continue;
290 }
291 MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
293 for (MainIDRelationsEntryItem *item = entry->from_ids; item; item = item->next) {
294 if (!ID_IS_LINKED(item->id_pointer.from)) {
295 directly_used_libs.add(id_iter->lib);
296 id_iter->lib->runtime->parent = nullptr;
297 break;
298 }
299 }
300 }
302
303 LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
304 /* A directly used library. */
305 if (directly_used_libs.contains(lib_iter)) {
306 BLI_assert(lib_iter->runtime->temp_index == 0);
307 continue;
308 }
309
310 /* Assume existing parent is still valid, since it was not cleared in previous loop above.
311 * Just compute 'hierarchy value' in temp index, if needed. */
312 if (lib_iter->runtime->parent) {
313 if (lib_iter->runtime->temp_index > 0) {
314 continue;
315 }
316 blender::Vector<Library *> parent_libraries;
317 for (Library *parent_lib_iter = lib_iter;
318 parent_lib_iter && parent_lib_iter->runtime->temp_index == 0;
319 parent_lib_iter = parent_lib_iter->runtime->parent)
320 {
321 parent_libraries.append(parent_lib_iter);
322 }
323 int parent_temp_index = parent_libraries.last()->runtime->temp_index +
324 int(parent_libraries.size()) - 1;
325 for (Library *parent_lib_iter : parent_libraries) {
326 BLI_assert(parent_lib_iter != parent_libraries.last() ||
327 parent_lib_iter->runtime->temp_index == parent_temp_index);
328 parent_lib_iter->runtime->temp_index = parent_temp_index--;
329 }
330 continue;
331 }
332
333 /* Otherwise, it's an indirectly used library with no known parent, another loop is needed to
334 * ensure all known hierarchy has valid indices when trying to find the best valid parent
335 * library. */
336 }
337
338 /* For all libraries known to be indirect, but without a known parent, find a best valid parent
339 * (i.e. a 'most directly used' library). */
340 LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
341 /* A directly used library. */
342 if (directly_used_libs.contains(lib_iter)) {
343 BLI_assert(lib_iter->runtime->temp_index == 0);
344 continue;
345 }
346
347 if (lib_iter->runtime->parent) {
348 BLI_assert(lib_iter->runtime->temp_index > 0);
349 }
350 else {
351 BLI_assert(lib_iter->runtime->temp_index == 0);
352 rebuild_hierarchy_best_parent_find(bmain, directly_used_libs, lib_iter);
353 }
354 }
355
357}
358
360 blender::StringRef filepath_abs)
361{
362 LISTBASE_FOREACH (Library *, lib_iter, libraries) {
363 if (filepath_abs == lib_iter->runtime->filepath_abs) {
364 return lib_iter;
365 }
366 }
367 return nullptr;
368}
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:125
IDTypeInfo IDType_ID_LI
Definition library.cc:141
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:46
@ IDTYPE_FLAGS_NO_LIBLINKING
Definition BKE_idtype.hh:32
@ IDTYPE_FLAGS_NEVER_UNUSED
Definition BKE_idtype.hh:69
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_NEVER_SELF
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:563
#define FOREACH_MAIN_LISTBASE_ID_END
Definition BKE_main.hh:532
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition BKE_main.hh:526
#define FOREACH_MAIN_LISTBASE_END
Definition BKE_main.hh:544
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition BKE_main.hh:537
void BKE_main_relations_create(Main *bmain, short flag)
Definition main.cc:549
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
void BKE_main_relations_free(Main *bmain)
Definition main.cc:586
void BKE_main_namemap_destroy(UniqueName_Map **r_name_map) ATTR_NONNULL()
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
#define LISTBASE_FOREACH(type, var, list)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define UNUSED_VARS_NDEBUG(...)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLT_I18NCONTEXT_ID_LIBRARY
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
ID and Library types, which are fundamental for SDNA.
@ INDEX_ID_LI
Definition DNA_ID.h:1189
BMesh const char void * data
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
#define ID_IS_LINKED(_id)
#define FILTER_ID_LI
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
Definition library.cc:171
void BKE_library_main_rebuild_hierarchy(Main *bmain)
Definition library.cc:270
static void library_runtime_reset(Library *lib)
Definition library.cc:45
static void rebuild_hierarchy_best_parent_find(Main *bmain, blender::Set< Library * > &directly_used_libs, Library *lib)
Definition library.cc:196
static void library_blend_read_data(BlendDataReader *, ID *id)
Definition library.cc:135
static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition library.cc:98
static void library_blend_write_data(BlendWriter *writer, ID *id, const void *id_address)
Definition library.cc:115
static void library_foreach_id(ID *id, LibraryForeachIDData *data)
Definition library.cc:92
static void library_init_data(ID *id)
Definition library.cc:50
static void library_copy_data(Main *bmain, std::optional< Library * > owner_library, ID *id_dst, const ID *id_src, int)
Definition library.cc:66
static void library_free_data(ID *id)
Definition library.cc:56
#define LOG(severity)
Definition log.h:32
Library * search_filepath_abs(ListBase *libraries, blender::StringRef filepath_abs)
Definition library.cc:359
Definition DNA_ID.h:404
struct Library * lib
Definition DNA_ID.h:410
struct PackedFile * packedfile
Definition DNA_ID.h:509
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
MainIDRelationsEntryItem * next
Definition BKE_main.hh:55
MainIDRelationsEntryItem * from_ids
Definition BKE_main.hh:72
GHash * relations_from_pointers
Definition BKE_main.hh:127
ListBase libraries
Definition BKE_main.hh:246
MainIDRelations * relations
Definition BKE_main.hh:298
#define N_(msgid)
static DynamicLibrary lib