1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup blenloader
22  */
23 
24 /**
25  *
26  * FILE FORMAT
27  * ===========
28  *
29  * IFF-style structure (but not IFF compatible!)
30  *
31  * Start file:
32  * <pre>
33  * `BLENDER_V100`  `12` bytes  (version 1.00 is just an example).
34  *                 `V` = big endian, `v` = little endian.
35  *                 `_` = 4 byte pointer, `-` = 8 byte pointer.
36  * </pre>
37  *
38  * data-blocks: (also see struct #BHead).
39  * <pre>
40  * `bh.code`       `char[4]` see `BLO_blend_defs.h` for a list of known types.
41  * `bh.len`        `int32` length data after #BHead in bytes.
42  * `bh.old`        `void *` old pointer (the address at the time of writing the file).
43  * `bh.SDNAnr`     `int32` struct index of structs stored in #DNA1 data.
44  * `bh.nr`         `int32` in case of array: number of structs.
45  * data
46  * ...
47  * ...
48  * </pre>
49  *
50  * Almost all data in Blender are structures. Each struct saved
51  * gets a BHead header.  With BHead the struct can be linked again
52  * and compared with #StructDNA.
53 
54  * WRITE
55  * =====
56  *
57  * Preferred writing order: (not really a must, but why would you do it random?)
58  * Any case: direct data is ALWAYS after the lib block.
59  *
60  * (Local file data)
61  * - for each LibBlock
62  *   - write LibBlock
63  *   - write associated direct data
64  * (External file data)
65  * - per library
66  *   - write library block
67  *   - per LibBlock
68  *     - write the ID of LibBlock
69  * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
70  * - write #GLOB (#FileGlobal struct) (some global vars).
71  * - write #DNA1 (#SDNA struct)
72  * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``.
73  */
74 
75 #include <fcntl.h>
76 #include <limits.h>
77 #include <math.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81 
82 #ifdef WIN32
83 #  include "BLI_winstuff.h"
84 #  include "winsock2.h"
85 #  include <io.h>
86 #  include <zlib.h> /* odd include order-issue */
87 #else
88 #  include <unistd.h> /* FreeBSD, for write() and close(). */
89 #endif
90 
91 #include "BLI_utildefines.h"
92 
93 /* allow writefile to use deprecated functionality (for forward compatibility code) */
94 #define DNA_DEPRECATED_ALLOW
95 
96 #include "DNA_anim_types.h"
97 #include "DNA_armature_types.h"
98 #include "DNA_cachefile_types.h"
99 #include "DNA_cloth_types.h"
100 #include "DNA_collection_types.h"
101 #include "DNA_constraint_types.h"
102 #include "DNA_curveprofile_types.h"
103 #include "DNA_dynamicpaint_types.h"
104 #include "DNA_fileglobal_types.h"
105 #include "DNA_fluid_types.h"
106 #include "DNA_genfile.h"
107 #include "DNA_lightprobe_types.h"
108 #include "DNA_meshdata_types.h"
109 #include "DNA_movieclip_types.h"
110 #include "DNA_object_force_types.h"
111 #include "DNA_object_types.h"
112 #include "DNA_particle_types.h"
113 #include "DNA_pointcache_types.h"
114 #include "DNA_rigidbody_types.h"
115 #include "DNA_scene_types.h"
116 #include "DNA_screen_types.h"
117 #include "DNA_sdna_types.h"
118 #include "DNA_sequence_types.h"
119 #include "DNA_shader_fx_types.h"
120 #include "DNA_space_types.h"
121 #include "DNA_view3d_types.h"
122 #include "DNA_windowmanager_types.h"
123 #include "DNA_workspace_types.h"
124 
125 #include "BLI_bitmap.h"
126 #include "BLI_blenlib.h"
127 #include "BLI_mempool.h"
128 #include "MEM_guardedalloc.h" /* MEM_freeN */
129 
130 #include "BKE_action.h"
131 #include "BKE_anim_data.h"
132 #include "BKE_animsys.h"
133 #include "BKE_armature.h"
134 #include "BKE_blender_version.h"
135 #include "BKE_bpath.h"
136 #include "BKE_collection.h"
137 #include "BKE_colortools.h"
138 #include "BKE_constraint.h"
139 #include "BKE_curveprofile.h"
140 #include "BKE_deform.h"
141 #include "BKE_fcurve.h"
142 #include "BKE_fcurve_driver.h"
143 #include "BKE_global.h" /* for G */
144 #include "BKE_gpencil_modifier.h"
145 #include "BKE_icons.h"
146 #include "BKE_idprop.h"
147 #include "BKE_idtype.h"
148 #include "BKE_layer.h"
149 #include "BKE_lib_id.h"
150 #include "BKE_lib_override.h"
151 #include "BKE_main.h"
152 #include "BKE_modifier.h"
153 #include "BKE_node.h"
154 #include "BKE_object.h"
155 #include "BKE_packedFile.h"
156 #include "BKE_pointcache.h"
157 #include "BKE_report.h"
158 #include "BKE_sequencer.h"
159 #include "BKE_shader_fx.h"
160 #include "BKE_subsurf.h"
161 #include "BKE_workspace.h"
162 
163 #include "BLO_blend_defs.h"
164 #include "BLO_blend_validate.h"
165 #include "BLO_read_write.h"
166 #include "BLO_readfile.h"
167 #include "BLO_undofile.h"
168 #include "BLO_writefile.h"
169 
170 #include "readfile.h"
171 
172 #include <errno.h>
173 
174 /* Make preferences read-only. */
175 #define U (*((const UserDef *)&U))
176 
177 /* ********* my write, buffered writing with minimum size chunks ************ */
178 
179 /* Use optimal allocation since blocks of this size are kept in memory for undo. */
180 #define MYWRITE_BUFFER_SIZE (MEM_SIZE_OPTIMAL(1 << 17)) /* 128kb */
181 #define MYWRITE_MAX_CHUNK (MEM_SIZE_OPTIMAL(1 << 15))   /* ~32kb */
182 
183 /** Use if we want to store how many bytes have been written to the file. */
184 // #define USE_WRITE_DATA_LEN
185 
186 /* -------------------------------------------------------------------- */
187 /** \name Internal Write Wrapper's (Abstracts Compression)
188  * \{ */
189 
190 typedef enum {
191   WW_WRAP_NONE = 1,
192   WW_WRAP_ZLIB,
193 } eWriteWrapType;
194 
195 typedef struct WriteWrap WriteWrap;
196 struct WriteWrap {
197   /* callbacks */
198   bool (*open)(WriteWrap *ww, const char *filepath);
199   bool (*close)(WriteWrap *ww);
200   size_t (*write)(WriteWrap *ww, const char *data, size_t data_len);
201 
202   /* Buffer output (we only want when output isn't already buffered). */
203   bool use_buf;
204 
205   /* internal */
206   union {
207     int file_handle;
208     gzFile gz_handle;
209   } _user_data;
210 };
211 
212 /* none */
213 #define FILE_HANDLE(ww) (ww)->_user_data.file_handle
214 
ww_open_none(WriteWrap * ww,const char * filepath)215 static bool ww_open_none(WriteWrap *ww, const char *filepath)
216 {
217   int file;
218 
219   file = BLI_open(filepath, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
220 
221   if (file != -1) {
222     FILE_HANDLE(ww) = file;
223     return true;
224   }
225 
226   return false;
227 }
ww_close_none(WriteWrap * ww)228 static bool ww_close_none(WriteWrap *ww)
229 {
230   return (close(FILE_HANDLE(ww)) != -1);
231 }
ww_write_none(WriteWrap * ww,const char * buf,size_t buf_len)232 static size_t ww_write_none(WriteWrap *ww, const char *buf, size_t buf_len)
233 {
234   return write(FILE_HANDLE(ww), buf, buf_len);
235 }
236 #undef FILE_HANDLE
237 
238 /* zlib */
239 #define FILE_HANDLE(ww) (ww)->_user_data.gz_handle
240 
ww_open_zlib(WriteWrap * ww,const char * filepath)241 static bool ww_open_zlib(WriteWrap *ww, const char *filepath)
242 {
243   gzFile file;
244 
245   file = BLI_gzopen(filepath, "wb1");
246 
247   if (file != Z_NULL) {
248     FILE_HANDLE(ww) = file;
249     return true;
250   }
251 
252   return false;
253 }
ww_close_zlib(WriteWrap * ww)254 static bool ww_close_zlib(WriteWrap *ww)
255 {
256   return (gzclose(FILE_HANDLE(ww)) == Z_OK);
257 }
ww_write_zlib(WriteWrap * ww,const char * buf,size_t buf_len)258 static size_t ww_write_zlib(WriteWrap *ww, const char *buf, size_t buf_len)
259 {
260   return gzwrite(FILE_HANDLE(ww), buf, buf_len);
261 }
262 #undef FILE_HANDLE
263 
264 /* --- end compression types --- */
265 
ww_handle_init(eWriteWrapType ww_type,WriteWrap * r_ww)266 static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww)
267 {
268   memset(r_ww, 0, sizeof(*r_ww));
269 
270   switch (ww_type) {
271     case WW_WRAP_ZLIB: {
272       r_ww->open = ww_open_zlib;
273       r_ww->close = ww_close_zlib;
274       r_ww->write = ww_write_zlib;
275       r_ww->use_buf = false;
276       break;
277     }
278     default: {
279       r_ww->open = ww_open_none;
280       r_ww->close = ww_close_none;
281       r_ww->write = ww_write_none;
282       r_ww->use_buf = true;
283       break;
284     }
285   }
286 }
287 
288 /** \} */
289 
290 /* -------------------------------------------------------------------- */
291 /** \name Write Data Type & Functions
292  * \{ */
293 
294 typedef struct {
295   const struct SDNA *sdna;
296 
297   /** Use for file and memory writing (fixed size of #MYWRITE_BUFFER_SIZE). */
298   uchar *buf;
299   /** Number of bytes used in #WriteData.buf (flushed when exceeded). */
300   size_t buf_used_len;
301 
302 #ifdef USE_WRITE_DATA_LEN
303   /** Total number of bytes written. */
304   size_t write_len;
305 #endif
306 
307   /** Set on unlikely case of an error (ignores further file writing).  */
308   bool error;
309 
310   /** #MemFile writing (used for undo). */
311   MemFileWriteData mem;
312   /** When true, write to #WriteData.current, could also call 'is_undo'. */
313   bool use_memfile;
314 
315   /**
316    * Wrap writing, so we can use zlib or
317    * other compression types later, see: G_FILE_COMPRESS
318    * Will be NULL for UNDO.
319    */
320   WriteWrap *ww;
321 } WriteData;
322 
323 typedef struct BlendWriter {
324   WriteData *wd;
325 } BlendWriter;
326 
writedata_new(WriteWrap * ww)327 static WriteData *writedata_new(WriteWrap *ww)
328 {
329   WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
330 
331   wd->sdna = DNA_sdna_current_get();
332 
333   wd->ww = ww;
334 
335   if ((ww == NULL) || (ww->use_buf)) {
336     wd->buf = MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
337   }
338 
339   return wd;
340 }
341 
writedata_do_write(WriteData * wd,const void * mem,size_t memlen)342 static void writedata_do_write(WriteData *wd, const void *mem, size_t memlen)
343 {
344   if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) {
345     return;
346   }
347 
348   if (memlen > INT_MAX) {
349     BLI_assert(!"Cannot write chunks bigger than INT_MAX.");
350     return;
351   }
352 
353   if (UNLIKELY(wd->error)) {
354     return;
355   }
356 
357   /* memory based save */
358   if (wd->use_memfile) {
359     BLO_memfile_chunk_add(&wd->mem, mem, memlen);
360   }
361   else {
362     if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
363       wd->error = true;
364     }
365   }
366 }
367 
writedata_free(WriteData * wd)368 static void writedata_free(WriteData *wd)
369 {
370   if (wd->buf) {
371     MEM_freeN(wd->buf);
372   }
373   MEM_freeN(wd);
374 }
375 
376 /** \} */
377 
378 /* -------------------------------------------------------------------- */
379 /** \name Local Writing API 'mywrite'
380  * \{ */
381 
382 /**
383  * Flush helps the de-duplicating memory for undo-save by logically segmenting data,
384  * so differences in one part of memory won't cause unrelated data to be duplicated.
385  */
mywrite_flush(WriteData * wd)386 static void mywrite_flush(WriteData *wd)
387 {
388   if (wd->buf_used_len != 0) {
389     writedata_do_write(wd, wd->buf, wd->buf_used_len);
390     wd->buf_used_len = 0;
391   }
392 }
393 
394 /**
395  * Low level WRITE(2) wrapper that buffers data
396  * \param adr: Pointer to new chunk of data
397  * \param len: Length of new chunk of data
398  */
mywrite(WriteData * wd,const void * adr,size_t len)399 static void mywrite(WriteData *wd, const void *adr, size_t len)
400 {
401   if (UNLIKELY(wd->error)) {
402     return;
403   }
404 
405   if (UNLIKELY(adr == NULL)) {
406     BLI_assert(0);
407     return;
408   }
409 
410 #ifdef USE_WRITE_DATA_LEN
411   wd->write_len += len;
412 #endif
413 
414   if (wd->buf == NULL) {
415     writedata_do_write(wd, adr, len);
416   }
417   else {
418     /* if we have a single big chunk, write existing data in
419      * buffer and write out big chunk in smaller pieces */
420     if (len > MYWRITE_MAX_CHUNK) {
421       if (wd->buf_used_len != 0) {
422         writedata_do_write(wd, wd->buf, wd->buf_used_len);
423         wd->buf_used_len = 0;
424       }
425 
426       do {
427         size_t writelen = MIN2(len, MYWRITE_MAX_CHUNK);
428         writedata_do_write(wd, adr, writelen);
429         adr = (const char *)adr + writelen;
430         len -= writelen;
431       } while (len > 0);
432 
433       return;
434     }
435 
436     /* if data would overflow buffer, write out the buffer */
437     if (len + wd->buf_used_len > MYWRITE_BUFFER_SIZE - 1) {
438       writedata_do_write(wd, wd->buf, wd->buf_used_len);
439       wd->buf_used_len = 0;
440     }
441 
442     /* append data at end of buffer */
443     memcpy(&wd->buf[wd->buf_used_len], adr, len);
444     wd->buf_used_len += len;
445   }
446 }
447 
448 /**
449  * BeGiN initializer for mywrite
450  * \param ww: File write wrapper.
451  * \param compare: Previous memory file (can be NULL).
452  * \param current: The current memory file (can be NULL).
453  * \warning Talks to other functions with global parameters
454  */
mywrite_begin(WriteWrap * ww,MemFile * compare,MemFile * current)455 static WriteData *mywrite_begin(WriteWrap *ww, MemFile *compare, MemFile *current)
456 {
457   WriteData *wd = writedata_new(ww);
458 
459   if (current != NULL) {
460     BLO_memfile_write_init(&wd->mem, current, compare);
461     wd->use_memfile = true;
462   }
463 
464   return wd;
465 }
466 
467 /**
468  * END the mywrite wrapper
469  * \return 1 if write failed
470  * \return unknown global variable otherwise
471  * \warning Talks to other functions with global parameters
472  */
mywrite_end(WriteData * wd)473 static bool mywrite_end(WriteData *wd)
474 {
475   if (wd->buf_used_len != 0) {
476     writedata_do_write(wd, wd->buf, wd->buf_used_len);
477     wd->buf_used_len = 0;
478   }
479 
480   if (wd->use_memfile) {
481     BLO_memfile_write_finalize(&wd->mem);
482   }
483 
484   const bool err = wd->error;
485   writedata_free(wd);
486 
487   return err;
488 }
489 
490 /**
491  * Start writing of data related to a single ID.
492  *
493  * Only does something when storing an undo step.
494  */
mywrite_id_begin(WriteData * wd,ID * id)495 static void mywrite_id_begin(WriteData *wd, ID *id)
496 {
497   if (wd->use_memfile) {
498     wd->mem.current_id_session_uuid = id->session_uuid;
499 
500     /* If current next memchunk does not match the ID we are about to write, try to find the
501      * correct memchunk in the mapping using ID's session_uuid. */
502     if (wd->mem.id_session_uuid_mapping != NULL &&
503         (wd->mem.reference_current_chunk == NULL ||
504          wd->mem.reference_current_chunk->id_session_uuid != id->session_uuid)) {
505       void *ref = BLI_ghash_lookup(wd->mem.id_session_uuid_mapping,
506                                    POINTER_FROM_UINT(id->session_uuid));
507       if (ref != NULL) {
508         wd->mem.reference_current_chunk = ref;
509       }
510       /* Else, no existing memchunk found, i.e. this is supposed to be a new ID. */
511     }
512     /* Otherwise, we try with the current memchunk in any case, whether it is matching current
513      * ID's session_uuid or not. */
514   }
515 }
516 
517 /**
518  * Start writing of data related to a single ID.
519  *
520  * Only does something when storing an undo step.
521  */
mywrite_id_end(WriteData * wd,ID * UNUSED (id))522 static void mywrite_id_end(WriteData *wd, ID *UNUSED(id))
523 {
524   if (wd->use_memfile) {
525     /* Very important to do it after every ID write now, otherwise we cannot know whether a
526      * specific ID changed or not. */
527     mywrite_flush(wd);
528     wd->mem.current_id_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
529   }
530 }
531 
532 /** \} */
533 
534 /* -------------------------------------------------------------------- */
535 /** \name Generic DNA File Writing
536  * \{ */
537 
writestruct_at_address_nr(WriteData * wd,int filecode,const int struct_nr,int nr,const void * adr,const void * data)538 static void writestruct_at_address_nr(
539     WriteData *wd, int filecode, const int struct_nr, int nr, const void *adr, const void *data)
540 {
541   BHead bh;
542 
543   BLI_assert(struct_nr > 0 && struct_nr < SDNA_TYPE_MAX);
544 
545   if (adr == NULL || data == NULL || nr == 0) {
546     return;
547   }
548 
549   /* init BHead */
550   bh.code = filecode;
551   bh.old = adr;
552   bh.nr = nr;
553 
554   bh.SDNAnr = struct_nr;
555   const SDNA_Struct *struct_info = wd->sdna->structs[bh.SDNAnr];
556 
557   bh.len = nr * wd->sdna->types_size[struct_info->type];
558 
559   if (bh.len == 0) {
560     return;
561   }
562 
563   mywrite(wd, &bh, sizeof(BHead));
564   mywrite(wd, data, (size_t)bh.len);
565 }
566 
writestruct_nr(WriteData * wd,int filecode,const int struct_nr,int nr,const void * adr)567 static void writestruct_nr(
568     WriteData *wd, int filecode, const int struct_nr, int nr, const void *adr)
569 {
570   writestruct_at_address_nr(wd, filecode, struct_nr, nr, adr, adr);
571 }
572 
573 /* do not use for structs */
writedata(WriteData * wd,int filecode,size_t len,const void * adr)574 static void writedata(WriteData *wd, int filecode, size_t len, const void *adr)
575 {
576   BHead bh;
577 
578   if (adr == NULL || len == 0) {
579     return;
580   }
581 
582   if (len > INT_MAX) {
583     BLI_assert(!"Cannot write chunks bigger than INT_MAX.");
584     return;
585   }
586 
587   /* align to 4 (writes uninitialized bytes in some cases) */
588   len = (len + 3) & ~((size_t)3);
589 
590   /* init BHead */
591   bh.code = filecode;
592   bh.old = adr;
593   bh.nr = 1;
594   bh.SDNAnr = 0;
595   bh.len = (int)len;
596 
597   mywrite(wd, &bh, sizeof(BHead));
598   mywrite(wd, adr, len);
599 }
600 
601 /* use this to force writing of lists in same order as reading (using link_list) */
writelist_nr(WriteData * wd,int filecode,const int struct_nr,const ListBase * lb)602 static void writelist_nr(WriteData *wd, int filecode, const int struct_nr, const ListBase *lb)
603 {
604   const Link *link = lb->first;
605 
606   while (link) {
607     writestruct_nr(wd, filecode, struct_nr, 1, link);
608     link = link->next;
609   }
610 }
611 
612 #if 0
613 static void writelist_id(WriteData *wd, int filecode, const char *structname, const ListBase *lb)
614 {
615   const Link *link = lb->first;
616   if (link) {
617 
618     const int struct_nr = DNA_struct_find_nr(wd->sdna, structname);
619     if (struct_nr == -1) {
620       printf("error: can't find SDNA code <%s>\n", structname);
621       return;
622     }
623 
624     while (link) {
625       writestruct_nr(wd, filecode, struct_nr, 1, link);
626       link = link->next;
627     }
628   }
629 }
630 #endif
631 
632 #define writestruct_at_address(wd, filecode, struct_id, nr, adr, data) \
633   writestruct_at_address_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr, data)
634 
635 #define writestruct(wd, filecode, struct_id, nr, adr) \
636   writestruct_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr)
637 
638 #define writelist(wd, filecode, struct_id, lb) \
639   writelist_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), lb)
640 
641 /** \} */
642 
643 /* -------------------------------------------------------------------- */
644 /** \name Typed DNA File Writing
645  *
646  * These functions are used by blender's .blend system for file saving/loading.
647  * \{ */
648 
649 /**
650  * Take care using 'use_active_win', since we wont want the currently active window
651  * to change which scene renders (currently only used for undo).
652  */
current_screen_compat(Main * mainvar,bool use_active_win,bScreen ** r_screen,Scene ** r_scene,ViewLayer ** r_view_layer)653 static void current_screen_compat(Main *mainvar,
654                                   bool use_active_win,
655                                   bScreen **r_screen,
656                                   Scene **r_scene,
657                                   ViewLayer **r_view_layer)
658 {
659   wmWindowManager *wm;
660   wmWindow *window = NULL;
661 
662   /* find a global current screen in the first open window, to have
663    * a reasonable default for reading in older versions */
664   wm = mainvar->wm.first;
665 
666   if (wm) {
667     if (use_active_win) {
668       /* write the active window into the file, needed for multi-window undo T43424 */
669       for (window = wm->windows.first; window; window = window->next) {
670         if (window->active) {
671           break;
672         }
673       }
674 
675       /* fallback */
676       if (window == NULL) {
677         window = wm->windows.first;
678       }
679     }
680     else {
681       window = wm->windows.first;
682     }
683   }
684 
685   *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL;
686   *r_scene = (window) ? window->scene : NULL;
687   *r_view_layer = (window && *r_scene) ? BKE_view_layer_find(*r_scene, window->view_layer_name) :
688                                          NULL;
689 }
690 
691 typedef struct RenderInfo {
692   int sfra;
693   int efra;
694   char scene_name[MAX_ID_NAME - 2];
695 } RenderInfo;
696 
697 /**
698  * This was originally added for the historic render-daemon feature,
699  * now write because it can be easily extracted without reading the whole blend file.
700  *
701  * See: `release/scripts/modules/blend_render_info.py`
702  */
write_renderinfo(WriteData * wd,Main * mainvar)703 static void write_renderinfo(WriteData *wd, Main *mainvar)
704 {
705   bScreen *curscreen;
706   Scene *curscene = NULL;
707   ViewLayer *view_layer;
708 
709   /* XXX in future, handle multiple windows with multiple screens? */
710   current_screen_compat(mainvar, false, &curscreen, &curscene, &view_layer);
711 
712   LISTBASE_FOREACH (Scene *, sce, &mainvar->scenes) {
713     if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
714       RenderInfo data;
715       data.sfra = sce->r.sfra;
716       data.efra = sce->r.efra;
717       memset(data.scene_name, 0, sizeof(data.scene_name));
718 
719       BLI_strncpy(data.scene_name, sce->id.name + 2, sizeof(data.scene_name));
720 
721       writedata(wd, REND, sizeof(data), &data);
722     }
723   }
724 }
725 
write_keymapitem(BlendWriter * writer,const wmKeyMapItem * kmi)726 static void write_keymapitem(BlendWriter *writer, const wmKeyMapItem *kmi)
727 {
728   BLO_write_struct(writer, wmKeyMapItem, kmi);
729   if (kmi->properties) {
730     IDP_BlendWrite(writer, kmi->properties);
731   }
732 }
733 
write_userdef(BlendWriter * writer,const UserDef * userdef)734 static void write_userdef(BlendWriter *writer, const UserDef *userdef)
735 {
736   writestruct(writer->wd, USER, UserDef, 1, userdef);
737 
738   LISTBASE_FOREACH (const bTheme *, btheme, &userdef->themes) {
739     BLO_write_struct(writer, bTheme, btheme);
740   }
741 
742   LISTBASE_FOREACH (const wmKeyMap *, keymap, &userdef->user_keymaps) {
743     BLO_write_struct(writer, wmKeyMap, keymap);
744 
745     LISTBASE_FOREACH (const wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
746       BLO_write_struct(writer, wmKeyMapDiffItem, kmdi);
747       if (kmdi->remove_item) {
748         write_keymapitem(writer, kmdi->remove_item);
749       }
750       if (kmdi->add_item) {
751         write_keymapitem(writer, kmdi->add_item);
752       }
753     }
754 
755     LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &keymap->items) {
756       write_keymapitem(writer, kmi);
757     }
758   }
759 
760   LISTBASE_FOREACH (const wmKeyConfigPref *, kpt, &userdef->user_keyconfig_prefs) {
761     BLO_write_struct(writer, wmKeyConfigPref, kpt);
762     if (kpt->prop) {
763       IDP_BlendWrite(writer, kpt->prop);
764     }
765   }
766 
767   LISTBASE_FOREACH (const bUserMenu *, um, &userdef->user_menus) {
768     BLO_write_struct(writer, bUserMenu, um);
769     LISTBASE_FOREACH (const bUserMenuItem *, umi, &um->items) {
770       if (umi->type == USER_MENU_TYPE_OPERATOR) {
771         const bUserMenuItem_Op *umi_op = (const bUserMenuItem_Op *)umi;
772         BLO_write_struct(writer, bUserMenuItem_Op, umi_op);
773         if (umi_op->prop) {
774           IDP_BlendWrite(writer, umi_op->prop);
775         }
776       }
777       else if (umi->type == USER_MENU_TYPE_MENU) {
778         const bUserMenuItem_Menu *umi_mt = (const bUserMenuItem_Menu *)umi;
779         BLO_write_struct(writer, bUserMenuItem_Menu, umi_mt);
780       }
781       else if (umi->type == USER_MENU_TYPE_PROP) {
782         const bUserMenuItem_Prop *umi_pr = (const bUserMenuItem_Prop *)umi;
783         BLO_write_struct(writer, bUserMenuItem_Prop, umi_pr);
784       }
785       else {
786         BLO_write_struct(writer, bUserMenuItem, umi);
787       }
788     }
789   }
790 
791   LISTBASE_FOREACH (const bAddon *, bext, &userdef->addons) {
792     BLO_write_struct(writer, bAddon, bext);
793     if (bext->prop) {
794       IDP_BlendWrite(writer, bext->prop);
795     }
796   }
797 
798   LISTBASE_FOREACH (const bPathCompare *, path_cmp, &userdef->autoexec_paths) {
799     BLO_write_struct(writer, bPathCompare, path_cmp);
800   }
801 
802   LISTBASE_FOREACH (const uiStyle *, style, &userdef->uistyles) {
803     BLO_write_struct(writer, uiStyle, style);
804   }
805 }
806 
write_boid_state(BlendWriter * writer,BoidState * state)807 static void write_boid_state(BlendWriter *writer, BoidState *state)
808 {
809   BLO_write_struct(writer, BoidState, state);
810 
811   LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
812     switch (rule->type) {
813       case eBoidRuleType_Goal:
814       case eBoidRuleType_Avoid:
815         BLO_write_struct(writer, BoidRuleGoalAvoid, rule);
816         break;
817       case eBoidRuleType_AvoidCollision:
818         BLO_write_struct(writer, BoidRuleAvoidCollision, rule);
819         break;
820       case eBoidRuleType_FollowLeader:
821         BLO_write_struct(writer, BoidRuleFollowLeader, rule);
822         break;
823       case eBoidRuleType_AverageSpeed:
824         BLO_write_struct(writer, BoidRuleAverageSpeed, rule);
825         break;
826       case eBoidRuleType_Fight:
827         BLO_write_struct(writer, BoidRuleFight, rule);
828         break;
829       default:
830         BLO_write_struct(writer, BoidRule, rule);
831         break;
832     }
833   }
834 #if 0
835   BoidCondition *cond = state->conditions.first;
836   for (; cond; cond = cond->next) {
837     BLO_write_struct(writer, BoidCondition, cond);
838   }
839 #endif
840 }
841 
842 /* update this also to readfile.c */
843 static const char *ptcache_data_struct[] = {
844     "",          // BPHYS_DATA_INDEX
845     "",          // BPHYS_DATA_LOCATION
846     "",          // BPHYS_DATA_VELOCITY
847     "",          // BPHYS_DATA_ROTATION
848     "",          // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
849     "",          // BPHYS_DATA_SIZE:
850     "",          // BPHYS_DATA_TIMES:
851     "BoidData",  // case BPHYS_DATA_BOIDS:
852 };
853 static const char *ptcache_extra_struct[] = {
854     "",
855     "ParticleSpring",
856     "vec3f",
857 };
write_pointcaches(BlendWriter * writer,ListBase * ptcaches)858 static void write_pointcaches(BlendWriter *writer, ListBase *ptcaches)
859 {
860   LISTBASE_FOREACH (PointCache *, cache, ptcaches) {
861     BLO_write_struct(writer, PointCache, cache);
862 
863     if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
864       LISTBASE_FOREACH (PTCacheMem *, pm, &cache->mem_cache) {
865         BLO_write_struct(writer, PTCacheMem, pm);
866 
867         for (int i = 0; i < BPHYS_TOT_DATA; i++) {
868           if (pm->data[i] && pm->data_types & (1 << i)) {
869             if (ptcache_data_struct[i][0] == '\0') {
870               BLO_write_raw(writer, MEM_allocN_len(pm->data[i]), pm->data[i]);
871             }
872             else {
873               BLO_write_struct_array_by_name(
874                   writer, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
875             }
876           }
877         }
878 
879         LISTBASE_FOREACH (PTCacheExtra *, extra, &pm->extradata) {
880           if (ptcache_extra_struct[extra->type][0] == '\0') {
881             continue;
882           }
883           BLO_write_struct(writer, PTCacheExtra, extra);
884           BLO_write_struct_array_by_name(
885               writer, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
886         }
887       }
888     }
889   }
890 }
891 
write_particlesettings(BlendWriter * writer,ParticleSettings * part,const void * id_address)892 static void write_particlesettings(BlendWriter *writer,
893                                    ParticleSettings *part,
894                                    const void *id_address)
895 {
896   if (part->id.us > 0 || BLO_write_is_undo(writer)) {
897     /* write LibData */
898     BLO_write_id_struct(writer, ParticleSettings, id_address, &part->id);
899     BKE_id_blend_write(writer, &part->id);
900 
901     if (part->adt) {
902       BKE_animdata_blend_write(writer, part->adt);
903     }
904     BLO_write_struct(writer, PartDeflect, part->pd);
905     BLO_write_struct(writer, PartDeflect, part->pd2);
906     BLO_write_struct(writer, EffectorWeights, part->effector_weights);
907 
908     if (part->clumpcurve) {
909       BKE_curvemapping_blend_write(writer, part->clumpcurve);
910     }
911     if (part->roughcurve) {
912       BKE_curvemapping_blend_write(writer, part->roughcurve);
913     }
914     if (part->twistcurve) {
915       BKE_curvemapping_blend_write(writer, part->twistcurve);
916     }
917 
918     LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
919       /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
920       if (dw->ob != NULL) {
921         dw->index = 0;
922         if (part->instance_collection) { /* can be NULL if lining fails or set to None */
923           FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (part->instance_collection, object) {
924             if (object == dw->ob) {
925               break;
926             }
927             dw->index++;
928           }
929           FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
930         }
931       }
932       BLO_write_struct(writer, ParticleDupliWeight, dw);
933     }
934 
935     if (part->boids && part->phystype == PART_PHYS_BOIDS) {
936       BLO_write_struct(writer, BoidSettings, part->boids);
937 
938       LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
939         write_boid_state(writer, state);
940       }
941     }
942     if (part->fluid && part->phystype == PART_PHYS_FLUID) {
943       BLO_write_struct(writer, SPHFluidSettings, part->fluid);
944     }
945 
946     for (int a = 0; a < MAX_MTEX; a++) {
947       if (part->mtex[a]) {
948         BLO_write_struct(writer, MTex, part->mtex[a]);
949       }
950     }
951   }
952 }
953 
write_particlesystems(BlendWriter * writer,ListBase * particles)954 static void write_particlesystems(BlendWriter *writer, ListBase *particles)
955 {
956   LISTBASE_FOREACH (ParticleSystem *, psys, particles) {
957     BLO_write_struct(writer, ParticleSystem, psys);
958 
959     if (psys->particles) {
960       BLO_write_struct_array(writer, ParticleData, psys->totpart, psys->particles);
961 
962       if (psys->particles->hair) {
963         ParticleData *pa = psys->particles;
964 
965         for (int a = 0; a < psys->totpart; a++, pa++) {
966           BLO_write_struct_array(writer, HairKey, pa->totkey, pa->hair);
967         }
968       }
969 
970       if (psys->particles->boid && (psys->part->phystype == PART_PHYS_BOIDS)) {
971         BLO_write_struct_array(writer, BoidParticle, psys->totpart, psys->particles->boid);
972       }
973 
974       if (psys->part->fluid && (psys->part->phystype == PART_PHYS_FLUID) &&
975           (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) {
976         BLO_write_struct_array(
977             writer, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs);
978       }
979     }
980     LISTBASE_FOREACH (ParticleTarget *, pt, &psys->targets) {
981       BLO_write_struct(writer, ParticleTarget, pt);
982     }
983 
984     if (psys->child) {
985       BLO_write_struct_array(writer, ChildParticle, psys->totchild, psys->child);
986     }
987 
988     if (psys->clmd) {
989       BLO_write_struct(writer, ClothModifierData, psys->clmd);
990       BLO_write_struct(writer, ClothSimSettings, psys->clmd->sim_parms);
991       BLO_write_struct(writer, ClothCollSettings, psys->clmd->coll_parms);
992     }
993 
994     write_pointcaches(writer, &psys->ptcaches);
995   }
996 }
997 
write_motionpath(BlendWriter * writer,bMotionPath * mpath)998 static void write_motionpath(BlendWriter *writer, bMotionPath *mpath)
999 {
1000   /* sanity checks */
1001   if (mpath == NULL) {
1002     return;
1003   }
1004 
1005   /* firstly, just write the motionpath struct */
1006   BLO_write_struct(writer, bMotionPath, mpath);
1007 
1008   /* now write the array of data */
1009   BLO_write_struct_array(writer, bMotionPathVert, mpath->length, mpath->points);
1010 }
1011 
write_constraints(BlendWriter * writer,ListBase * conlist)1012 static void write_constraints(BlendWriter *writer, ListBase *conlist)
1013 {
1014   LISTBASE_FOREACH (bConstraint *, con, conlist) {
1015     const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
1016 
1017     /* Write the specific data */
1018     if (cti && con->data) {
1019       /* firstly, just write the plain con->data struct */
1020       BLO_write_struct_by_name(writer, cti->structName, con->data);
1021 
1022       /* do any constraint specific stuff */
1023       switch (con->type) {
1024         case CONSTRAINT_TYPE_PYTHON: {
1025           bPythonConstraint *data = con->data;
1026 
1027           /* write targets */
1028           LISTBASE_FOREACH (bConstraintTarget *, ct, &data->targets) {
1029             BLO_write_struct(writer, bConstraintTarget, ct);
1030           }
1031 
1032           /* Write ID Properties -- and copy this comment EXACTLY for easy finding
1033            * of library blocks that implement this.*/
1034           IDP_BlendWrite(writer, data->prop);
1035 
1036           break;
1037         }
1038         case CONSTRAINT_TYPE_ARMATURE: {
1039           bArmatureConstraint *data = con->data;
1040 
1041           /* write targets */
1042           LISTBASE_FOREACH (bConstraintTarget *, ct, &data->targets) {
1043             BLO_write_struct(writer, bConstraintTarget, ct);
1044           }
1045 
1046           break;
1047         }
1048         case CONSTRAINT_TYPE_SPLINEIK: {
1049           bSplineIKConstraint *data = con->data;
1050 
1051           /* write points array */
1052           BLO_write_float_array(writer, data->numpoints, data->points);
1053 
1054           break;
1055         }
1056       }
1057     }
1058 
1059     /* Write the constraint */
1060     BLO_write_struct(writer, bConstraint, con);
1061   }
1062 }
1063 
write_pose(BlendWriter * writer,bPose * pose,bArmature * arm)1064 static void write_pose(BlendWriter *writer, bPose *pose, bArmature *arm)
1065 {
1066   /* Write each channel */
1067   if (pose == NULL) {
1068     return;
1069   }
1070 
1071   BLI_assert(arm != NULL);
1072 
1073   /* Write channels */
1074   LISTBASE_FOREACH (bPoseChannel *, chan, &pose->chanbase) {
1075     /* Write ID Properties -- and copy this comment EXACTLY for easy finding
1076      * of library blocks that implement this.*/
1077     if (chan->prop) {
1078       IDP_BlendWrite(writer, chan->prop);
1079     }
1080 
1081     write_constraints(writer, &chan->constraints);
1082 
1083     write_motionpath(writer, chan->mpath);
1084 
1085     /* Prevent crashes with autosave,
1086      * when a bone duplicated in edit-mode has not yet been assigned to its pose-channel.
1087      * Also needed with memundo, in some cases we can store a step before pose has been
1088      * properly rebuilt from previous undo step. */
1089     Bone *bone = (pose->flag & POSE_RECALC) ? BKE_armature_find_bone_name(arm, chan->name) :
1090                                               chan->bone;
1091     if (bone != NULL) {
1092       /* gets restored on read, for library armatures */
1093       chan->selectflag = bone->flag & BONE_SELECTED;
1094     }
1095 
1096     BLO_write_struct(writer, bPoseChannel, chan);
1097   }
1098 
1099   /* Write groups */
1100   LISTBASE_FOREACH (bActionGroup *, grp, &pose->agroups) {
1101     BLO_write_struct(writer, bActionGroup, grp);
1102   }
1103 
1104   /* write IK param */
1105   if (pose->ikparam) {
1106     const char *structname = BKE_pose_ikparam_get_name(pose);
1107     if (structname) {
1108       BLO_write_struct_by_name(writer, structname, pose->ikparam);
1109     }
1110   }
1111 
1112   /* Write this pose */
1113   BLO_write_struct(writer, bPose, pose);
1114 }
1115 
write_defgroups(BlendWriter * writer,ListBase * defbase)1116 static void write_defgroups(BlendWriter *writer, ListBase *defbase)
1117 {
1118   LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) {
1119     BLO_write_struct(writer, bDeformGroup, defgroup);
1120   }
1121 }
1122 
write_fmaps(BlendWriter * writer,ListBase * fbase)1123 static void write_fmaps(BlendWriter *writer, ListBase *fbase)
1124 {
1125   LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
1126     BLO_write_struct(writer, bFaceMap, fmap);
1127   }
1128 }
1129 
write_modifiers(BlendWriter * writer,ListBase * modbase)1130 static void write_modifiers(BlendWriter *writer, ListBase *modbase)
1131 {
1132   if (modbase == NULL) {
1133     return;
1134   }
1135 
1136   LISTBASE_FOREACH (ModifierData *, md, modbase) {
1137     const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
1138     if (mti == NULL) {
1139       return;
1140     }
1141 
1142     BLO_write_struct_by_name(writer, mti->structName, md);
1143 
1144     if (md->type == eModifierType_Cloth) {
1145       ClothModifierData *clmd = (ClothModifierData *)md;
1146 
1147       BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
1148       BLO_write_struct(writer, ClothCollSettings, clmd->coll_parms);
1149       BLO_write_struct(writer, EffectorWeights, clmd->sim_parms->effector_weights);
1150       write_pointcaches(writer, &clmd->ptcaches);
1151     }
1152     else if (md->type == eModifierType_Fluid) {
1153       FluidModifierData *fmd = (FluidModifierData *)md;
1154 
1155       if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
1156         BLO_write_struct(writer, FluidDomainSettings, fmd->domain);
1157 
1158         if (fmd->domain) {
1159           write_pointcaches(writer, &(fmd->domain->ptcaches[0]));
1160 
1161           /* create fake pointcache so that old blender versions can read it */
1162           fmd->domain->point_cache[1] = BKE_ptcache_add(&fmd->domain->ptcaches[1]);
1163           fmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
1164           fmd->domain->point_cache[1]->step = 1;
1165 
1166           write_pointcaches(writer, &(fmd->domain->ptcaches[1]));
1167 
1168           if (fmd->domain->coba) {
1169             BLO_write_struct(writer, ColorBand, fmd->domain->coba);
1170           }
1171 
1172           /* cleanup the fake pointcache */
1173           BKE_ptcache_free_list(&fmd->domain->ptcaches[1]);
1174           fmd->domain->point_cache[1] = NULL;
1175 
1176           BLO_write_struct(writer, EffectorWeights, fmd->domain->effector_weights);
1177         }
1178       }
1179       else if (fmd->type & MOD_FLUID_TYPE_FLOW) {
1180         BLO_write_struct(writer, FluidFlowSettings, fmd->flow);
1181       }
1182       else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
1183         BLO_write_struct(writer, FluidEffectorSettings, fmd->effector);
1184       }
1185     }
1186     else if (md->type == eModifierType_Fluidsim) {
1187       FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
1188 
1189       BLO_write_struct(writer, FluidsimSettings, fluidmd->fss);
1190     }
1191     else if (md->type == eModifierType_DynamicPaint) {
1192       DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
1193 
1194       if (pmd->canvas) {
1195         BLO_write_struct(writer, DynamicPaintCanvasSettings, pmd->canvas);
1196 
1197         /* write surfaces */
1198         LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
1199           BLO_write_struct(writer, DynamicPaintSurface, surface);
1200         }
1201         /* write caches and effector weights */
1202         LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
1203           write_pointcaches(writer, &(surface->ptcaches));
1204 
1205           BLO_write_struct(writer, EffectorWeights, surface->effector_weights);
1206         }
1207       }
1208       if (pmd->brush) {
1209         BLO_write_struct(writer, DynamicPaintBrushSettings, pmd->brush);
1210         BLO_write_struct(writer, ColorBand, pmd->brush->paint_ramp);
1211         BLO_write_struct(writer, ColorBand, pmd->brush->vel_ramp);
1212       }
1213     }
1214     else if (md->type == eModifierType_Collision) {
1215 
1216 #if 0
1217       CollisionModifierData *collmd = (CollisionModifierData *)md;
1218       // TODO: CollisionModifier should use pointcache
1219       // + have proper reset events before enabling this
1220       writestruct(wd, DATA, MVert, collmd->numverts, collmd->x);
1221       writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew);
1222       writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
1223 #endif
1224     }
1225 
1226     if (mti->blendWrite != NULL) {
1227       mti->blendWrite(writer, md);
1228     }
1229   }
1230 }
1231 
write_gpencil_modifiers(BlendWriter * writer,ListBase * modbase)1232 static void write_gpencil_modifiers(BlendWriter *writer, ListBase *modbase)
1233 {
1234   if (modbase == NULL) {
1235     return;
1236   }
1237 
1238   LISTBASE_FOREACH (GpencilModifierData *, md, modbase) {
1239     const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
1240     if (mti == NULL) {
1241       return;
1242     }
1243 
1244     BLO_write_struct_by_name(writer, mti->struct_name, md);
1245 
1246     if (md->type == eGpencilModifierType_Thick) {
1247       ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
1248 
1249       if (gpmd->curve_thickness) {
1250         BKE_curvemapping_blend_write(writer, gpmd->curve_thickness);
1251       }
1252     }
1253     else if (md->type == eGpencilModifierType_Noise) {
1254       NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
1255 
1256       if (gpmd->curve_intensity) {
1257         BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1258       }
1259     }
1260     else if (md->type == eGpencilModifierType_Hook) {
1261       HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
1262 
1263       if (gpmd->curfalloff) {
1264         BKE_curvemapping_blend_write(writer, gpmd->curfalloff);
1265       }
1266     }
1267     else if (md->type == eGpencilModifierType_Tint) {
1268       TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
1269       if (gpmd->colorband) {
1270         BLO_write_struct(writer, ColorBand, gpmd->colorband);
1271       }
1272       if (gpmd->curve_intensity) {
1273         BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1274       }
1275     }
1276     else if (md->type == eGpencilModifierType_Smooth) {
1277       SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
1278       if (gpmd->curve_intensity) {
1279         BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1280       }
1281     }
1282     else if (md->type == eGpencilModifierType_Color) {
1283       ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
1284       if (gpmd->curve_intensity) {
1285         BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1286       }
1287     }
1288     else if (md->type == eGpencilModifierType_Opacity) {
1289       OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
1290       if (gpmd->curve_intensity) {
1291         BKE_curvemapping_blend_write(writer, gpmd->curve_intensity);
1292       }
1293     }
1294   }
1295 }
1296 
write_shaderfxs(BlendWriter * writer,ListBase * fxbase)1297 static void write_shaderfxs(BlendWriter *writer, ListBase *fxbase)
1298 {
1299   if (fxbase == NULL) {
1300     return;
1301   }
1302 
1303   LISTBASE_FOREACH (ShaderFxData *, fx, fxbase) {
1304     const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
1305     if (fxi == NULL) {
1306       return;
1307     }
1308 
1309     BLO_write_struct_by_name(writer, fxi->struct_name, fx);
1310   }
1311 }
1312 
write_object(BlendWriter * writer,Object * ob,const void * id_address)1313 static void write_object(BlendWriter *writer, Object *ob, const void *id_address)
1314 {
1315   const bool is_undo = BLO_write_is_undo(writer);
1316   if (ob->id.us > 0 || is_undo) {
1317     /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
1318     BKE_object_runtime_reset(ob);
1319 
1320     if (is_undo) {
1321       /* For undo we stay in object mode during undo presses, so keep edit-mode disabled on save as
1322        * well, can help reducing false detection of changed data-blocks. */
1323       ob->mode &= ~OB_MODE_EDIT;
1324     }
1325 
1326     /* write LibData */
1327     BLO_write_id_struct(writer, Object, id_address, &ob->id);
1328     BKE_id_blend_write(writer, &ob->id);
1329 
1330     if (ob->adt) {
1331       BKE_animdata_blend_write(writer, ob->adt);
1332     }
1333 
1334     /* direct data */
1335     BLO_write_pointer_array(writer, ob->totcol, ob->mat);
1336     BLO_write_raw(writer, sizeof(char) * ob->totcol, ob->matbits);
1337 
1338     bArmature *arm = NULL;
1339     if (ob->type == OB_ARMATURE) {
1340       arm = ob->data;
1341       if (arm && ob->pose && arm->act_bone) {
1342         BLI_strncpy(
1343             ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
1344       }
1345     }
1346 
1347     write_pose(writer, ob->pose, arm);
1348     write_defgroups(writer, &ob->defbase);
1349     write_fmaps(writer, &ob->fmaps);
1350     write_constraints(writer, &ob->constraints);
1351     write_motionpath(writer, ob->mpath);
1352 
1353     BLO_write_struct(writer, PartDeflect, ob->pd);
1354     if (ob->soft) {
1355       /* Set deprecated pointers to prevent crashes of older Blenders */
1356       ob->soft->pointcache = ob->soft->shared->pointcache;
1357       ob->soft->ptcaches = ob->soft->shared->ptcaches;
1358       BLO_write_struct(writer, SoftBody, ob->soft);
1359       BLO_write_struct(writer, SoftBody_Shared, ob->soft->shared);
1360       write_pointcaches(writer, &(ob->soft->shared->ptcaches));
1361       BLO_write_struct(writer, EffectorWeights, ob->soft->effector_weights);
1362     }
1363 
1364     if (ob->rigidbody_object) {
1365       /* TODO: if any extra data is added to handle duplis, will need separate function then */
1366       BLO_write_struct(writer, RigidBodyOb, ob->rigidbody_object);
1367     }
1368     if (ob->rigidbody_constraint) {
1369       BLO_write_struct(writer, RigidBodyCon, ob->rigidbody_constraint);
1370     }
1371 
1372     if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
1373       BLO_write_struct(writer, ImageUser, ob->iuser);
1374     }
1375 
1376     write_particlesystems(writer, &ob->particlesystem);
1377     write_modifiers(writer, &ob->modifiers);
1378     write_gpencil_modifiers(writer, &ob->greasepencil_modifiers);
1379     write_shaderfxs(writer, &ob->shader_fx);
1380 
1381     BLO_write_struct_list(writer, LinkData, &ob->pc_ids);
1382 
1383     BKE_previewimg_blend_write(writer, ob->preview);
1384   }
1385 }
1386 
write_collection_nolib(BlendWriter * writer,Collection * collection)1387 static void write_collection_nolib(BlendWriter *writer, Collection *collection)
1388 {
1389   /* Shared function for collection data-blocks and scene master collection. */
1390   BKE_previewimg_blend_write(writer, collection->preview);
1391 
1392   LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1393     BLO_write_struct(writer, CollectionObject, cob);
1394   }
1395 
1396   LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
1397     BLO_write_struct(writer, CollectionChild, child);
1398   }
1399 }
1400 
write_collection(BlendWriter * writer,Collection * collection,const void * id_address)1401 static void write_collection(BlendWriter *writer, Collection *collection, const void *id_address)
1402 {
1403   if (collection->id.us > 0 || BLO_write_is_undo(writer)) {
1404     /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
1405     collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
1406     collection->tag = 0;
1407     BLI_listbase_clear(&collection->object_cache);
1408     BLI_listbase_clear(&collection->parents);
1409 
1410     /* write LibData */
1411     BLO_write_id_struct(writer, Collection, id_address, &collection->id);
1412     BKE_id_blend_write(writer, &collection->id);
1413 
1414     write_collection_nolib(writer, collection);
1415   }
1416 }
1417 
write_sequence_modifiers(BlendWriter * writer,ListBase * modbase)1418 static void write_sequence_modifiers(BlendWriter *writer, ListBase *modbase)
1419 {
1420   LISTBASE_FOREACH (SequenceModifierData *, smd, modbase) {
1421     const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1422 
1423     if (smti) {
1424       BLO_write_struct_by_name(writer, smti->struct_name, smd);
1425 
1426       if (smd->type == seqModifierType_Curves) {
1427         CurvesModifierData *cmd = (CurvesModifierData *)smd;
1428 
1429         BKE_curvemapping_blend_write(writer, &cmd->curve_mapping);
1430       }
1431       else if (smd->type == seqModifierType_HueCorrect) {
1432         HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
1433 
1434         BKE_curvemapping_blend_write(writer, &hcmd->curve_mapping);
1435       }
1436     }
1437     else {
1438       BLO_write_struct(writer, SequenceModifierData, smd);
1439     }
1440   }
1441 }
1442 
write_view_settings(BlendWriter * writer,ColorManagedViewSettings * view_settings)1443 static void write_view_settings(BlendWriter *writer, ColorManagedViewSettings *view_settings)
1444 {
1445   if (view_settings->curve_mapping) {
1446     BKE_curvemapping_blend_write(writer, view_settings->curve_mapping);
1447   }
1448 }
1449 
write_view3dshading(BlendWriter * writer,View3DShading * shading)1450 static void write_view3dshading(BlendWriter *writer, View3DShading *shading)
1451 {
1452   if (shading->prop) {
1453     IDP_BlendWrite(writer, shading->prop);
1454   }
1455 }
1456 
write_paint(BlendWriter * writer,Paint * p)1457 static void write_paint(BlendWriter *writer, Paint *p)
1458 {
1459   if (p->cavity_curve) {
1460     BKE_curvemapping_blend_write(writer, p->cavity_curve);
1461   }
1462   BLO_write_struct_array(writer, PaintToolSlot, p->tool_slots_len, p->tool_slots);
1463 }
1464 
write_layer_collections(BlendWriter * writer,ListBase * lb)1465 static void write_layer_collections(BlendWriter *writer, ListBase *lb)
1466 {
1467   LISTBASE_FOREACH (LayerCollection *, lc, lb) {
1468     BLO_write_struct(writer, LayerCollection, lc);
1469 
1470     write_layer_collections(writer, &lc->layer_collections);
1471   }
1472 }
1473 
write_view_layer(BlendWriter * writer,ViewLayer * view_layer)1474 static void write_view_layer(BlendWriter *writer, ViewLayer *view_layer)
1475 {
1476   BLO_write_struct(writer, ViewLayer, view_layer);
1477   BLO_write_struct_list(writer, Base, &view_layer->object_bases);
1478 
1479   if (view_layer->id_properties) {
1480     IDP_BlendWrite(writer, view_layer->id_properties);
1481   }
1482 
1483   LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
1484     BLO_write_struct(writer, FreestyleModuleConfig, fmc);
1485   }
1486 
1487   LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
1488     BLO_write_struct(writer, FreestyleLineSet, fls);
1489   }
1490   write_layer_collections(writer, &view_layer->layer_collections);
1491 }
1492 
write_lightcache_texture(BlendWriter * writer,LightCacheTexture * tex)1493 static void write_lightcache_texture(BlendWriter *writer, LightCacheTexture *tex)
1494 {
1495   if (tex->data) {
1496     size_t data_size = tex->components * tex->tex_size[0] * tex->tex_size[1] * tex->tex_size[2];
1497     if (tex->data_type == LIGHTCACHETEX_FLOAT) {
1498       data_size *= sizeof(float);
1499     }
1500     else if (tex->data_type == LIGHTCACHETEX_UINT) {
1501       data_size *= sizeof(uint);
1502     }
1503 
1504     /* FIXME: We can't save more than what 32bit systems can handle.
1505      * The solution would be to split the texture but it is too late for 2.90. (see T78529) */
1506     if (data_size < INT_MAX) {
1507       BLO_write_raw(writer, data_size, tex->data);
1508     }
1509   }
1510 }
1511 
write_lightcache(BlendWriter * writer,LightCache * cache)1512 static void write_lightcache(BlendWriter *writer, LightCache *cache)
1513 {
1514   write_lightcache_texture(writer, &cache->grid_tx);
1515   write_lightcache_texture(writer, &cache->cube_tx);
1516 
1517   if (cache->cube_mips) {
1518     BLO_write_struct_array(writer, LightCacheTexture, cache->mips_len, cache->cube_mips);
1519     for (int i = 0; i < cache->mips_len; i++) {
1520       write_lightcache_texture(writer, &cache->cube_mips[i]);
1521     }
1522   }
1523 
1524   BLO_write_struct_array(writer, LightGridCache, cache->grid_len, cache->grid_data);
1525   BLO_write_struct_array(writer, LightProbeCache, cache->cube_len, cache->cube_data);
1526 }
1527 
write_scene(BlendWriter * writer,Scene * sce,const void * id_address)1528 static void write_scene(BlendWriter *writer, Scene *sce, const void *id_address)
1529 {
1530   if (BLO_write_is_undo(writer)) {
1531     /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
1532     /* XXX This UI data should not be stored in Scene at all... */
1533     memset(&sce->cursor, 0, sizeof(sce->cursor));
1534   }
1535 
1536   /* write LibData */
1537   BLO_write_id_struct(writer, Scene, id_address, &sce->id);
1538   BKE_id_blend_write(writer, &sce->id);
1539 
1540   if (sce->adt) {
1541     BKE_animdata_blend_write(writer, sce->adt);
1542   }
1543   BKE_keyingsets_blend_write(writer, &sce->keyingsets);
1544 
1545   /* direct data */
1546   ToolSettings *tos = sce->toolsettings;
1547   BLO_write_struct(writer, ToolSettings, tos);
1548   if (tos->vpaint) {
1549     BLO_write_struct(writer, VPaint, tos->vpaint);
1550     write_paint(writer, &tos->vpaint->paint);
1551   }
1552   if (tos->wpaint) {
1553     BLO_write_struct(writer, VPaint, tos->wpaint);
1554     write_paint(writer, &tos->wpaint->paint);
1555   }
1556   if (tos->sculpt) {
1557     BLO_write_struct(writer, Sculpt, tos->sculpt);
1558     write_paint(writer, &tos->sculpt->paint);
1559   }
1560   if (tos->uvsculpt) {
1561     BLO_write_struct(writer, UvSculpt, tos->uvsculpt);
1562     write_paint(writer, &tos->uvsculpt->paint);
1563   }
1564   if (tos->gp_paint) {
1565     BLO_write_struct(writer, GpPaint, tos->gp_paint);
1566     write_paint(writer, &tos->gp_paint->paint);
1567   }
1568   if (tos->gp_vertexpaint) {
1569     BLO_write_struct(writer, GpVertexPaint, tos->gp_vertexpaint);
1570     write_paint(writer, &tos->gp_vertexpaint->paint);
1571   }
1572   if (tos->gp_sculptpaint) {
1573     BLO_write_struct(writer, GpSculptPaint, tos->gp_sculptpaint);
1574     write_paint(writer, &tos->gp_sculptpaint->paint);
1575   }
1576   if (tos->gp_weightpaint) {
1577     BLO_write_struct(writer, GpWeightPaint, tos->gp_weightpaint);
1578     write_paint(writer, &tos->gp_weightpaint->paint);
1579   }
1580   /* write grease-pencil custom ipo curve to file */
1581   if (tos->gp_interpolate.custom_ipo) {
1582     BKE_curvemapping_blend_write(writer, tos->gp_interpolate.custom_ipo);
1583   }
1584   /* write grease-pencil multiframe falloff curve to file */
1585   if (tos->gp_sculpt.cur_falloff) {
1586     BKE_curvemapping_blend_write(writer, tos->gp_sculpt.cur_falloff);
1587   }
1588   /* write grease-pencil primitive curve to file */
1589   if (tos->gp_sculpt.cur_primitive) {
1590     BKE_curvemapping_blend_write(writer, tos->gp_sculpt.cur_primitive);
1591   }
1592   /* Write the curve profile to the file. */
1593   if (tos->custom_bevel_profile_preset) {
1594     BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset);
1595   }
1596 
1597   write_paint(writer, &tos->imapaint.paint);
1598 
1599   Editing *ed = sce->ed;
1600   if (ed) {
1601     Sequence *seq;
1602 
1603     BLO_write_struct(writer, Editing, ed);
1604 
1605     /* reset write flags too */
1606 
1607     SEQ_ALL_BEGIN (ed, seq) {
1608       if (seq->strip) {
1609         seq->strip->done = false;
1610       }
1611       BLO_write_struct(writer, Sequence, seq);
1612     }
1613     SEQ_ALL_END;
1614 
1615     SEQ_ALL_BEGIN (ed, seq) {
1616       if (seq->strip && seq->strip->done == 0) {
1617         /* write strip with 'done' at 0 because readfile */
1618 
1619         if (seq->effectdata) {
1620           switch (seq->type) {
1621             case SEQ_TYPE_COLOR:
1622               BLO_write_struct(writer, SolidColorVars, seq->effectdata);
1623               break;
1624             case SEQ_TYPE_SPEED:
1625               BLO_write_struct(writer, SpeedControlVars, seq->effectdata);
1626               break;
1627             case SEQ_TYPE_WIPE:
1628               BLO_write_struct(writer, WipeVars, seq->effectdata);
1629               break;
1630             case SEQ_TYPE_GLOW:
1631               BLO_write_struct(writer, GlowVars, seq->effectdata);
1632               break;
1633             case SEQ_TYPE_TRANSFORM:
1634               BLO_write_struct(writer, TransformVars, seq->effectdata);
1635               break;
1636             case SEQ_TYPE_GAUSSIAN_BLUR:
1637               BLO_write_struct(writer, GaussianBlurVars, seq->effectdata);
1638               break;
1639             case SEQ_TYPE_TEXT:
1640               BLO_write_struct(writer, TextVars, seq->effectdata);
1641               break;
1642             case SEQ_TYPE_COLORMIX:
1643               BLO_write_struct(writer, ColorMixVars, seq->effectdata);
1644               break;
1645           }
1646         }
1647 
1648         BLO_write_struct(writer, Stereo3dFormat, seq->stereo3d_format);
1649 
1650         Strip *strip = seq->strip;
1651         BLO_write_struct(writer, Strip, strip);
1652         if (strip->crop) {
1653           BLO_write_struct(writer, StripCrop, strip->crop);
1654         }
1655         if (strip->transform) {
1656           BLO_write_struct(writer, StripTransform, strip->transform);
1657         }
1658         if (strip->proxy) {
1659           BLO_write_struct(writer, StripProxy, strip->proxy);
1660         }
1661         if (seq->type == SEQ_TYPE_IMAGE) {
1662           BLO_write_struct_array(writer,
1663                                  StripElem,
1664                                  MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem),
1665                                  strip->stripdata);
1666         }
1667         else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
1668           BLO_write_struct(writer, StripElem, strip->stripdata);
1669         }
1670 
1671         strip->done = true;
1672       }
1673 
1674       if (seq->prop) {
1675         IDP_BlendWrite(writer, seq->prop);
1676       }
1677 
1678       write_sequence_modifiers(writer, &seq->modifiers);
1679     }
1680     SEQ_ALL_END;
1681 
1682     /* new; meta stack too, even when its nasty restore code */
1683     LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) {
1684       BLO_write_struct(writer, MetaStack, ms);
1685     }
1686   }
1687 
1688   if (sce->r.avicodecdata) {
1689     BLO_write_struct(writer, AviCodecData, sce->r.avicodecdata);
1690     if (sce->r.avicodecdata->lpFormat) {
1691       BLO_write_raw(writer, (size_t)sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
1692     }
1693     if (sce->r.avicodecdata->lpParms) {
1694       BLO_write_raw(writer, (size_t)sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
1695     }
1696   }
1697   if (sce->r.ffcodecdata.properties) {
1698     IDP_BlendWrite(writer, sce->r.ffcodecdata.properties);
1699   }
1700 
1701   /* writing dynamic list of TimeMarkers to the blend file */
1702   LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) {
1703     BLO_write_struct(writer, TimeMarker, marker);
1704 
1705     if (marker->prop != NULL) {
1706       IDP_BlendWrite(writer, marker->prop);
1707     }
1708   }
1709 
1710   /* writing dynamic list of TransformOrientations to the blend file */
1711   LISTBASE_FOREACH (TransformOrientation *, ts, &sce->transform_spaces) {
1712     BLO_write_struct(writer, TransformOrientation, ts);
1713   }
1714 
1715   /* writing MultiView to the blend file */
1716   LISTBASE_FOREACH (SceneRenderView *, srv, &sce->r.views) {
1717     BLO_write_struct(writer, SceneRenderView, srv);
1718   }
1719 
1720   if (sce->nodetree) {
1721     BLO_write_struct(writer, bNodeTree, sce->nodetree);
1722     ntreeBlendWrite(writer, sce->nodetree);
1723   }
1724 
1725   write_view_settings(writer, &sce->view_settings);
1726 
1727   /* writing RigidBodyWorld data to the blend file */
1728   if (sce->rigidbody_world) {
1729     /* Set deprecated pointers to prevent crashes of older Blenders */
1730     sce->rigidbody_world->pointcache = sce->rigidbody_world->shared->pointcache;
1731     sce->rigidbody_world->ptcaches = sce->rigidbody_world->shared->ptcaches;
1732     BLO_write_struct(writer, RigidBodyWorld, sce->rigidbody_world);
1733 
1734     BLO_write_struct(writer, RigidBodyWorld_Shared, sce->rigidbody_world->shared);
1735     BLO_write_struct(writer, EffectorWeights, sce->rigidbody_world->effector_weights);
1736     write_pointcaches(writer, &(sce->rigidbody_world->shared->ptcaches));
1737   }
1738 
1739   BKE_previewimg_blend_write(writer, sce->preview);
1740   BKE_curvemapping_curves_blend_write(writer, &sce->r.mblur_shutter_curve);
1741 
1742   LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
1743     write_view_layer(writer, view_layer);
1744   }
1745 
1746   if (sce->master_collection) {
1747     BLO_write_struct(writer, Collection, sce->master_collection);
1748     write_collection_nolib(writer, sce->master_collection);
1749   }
1750 
1751   /* Eevee Lightcache */
1752   if (sce->eevee.light_cache_data && !BLO_write_is_undo(writer)) {
1753     BLO_write_struct(writer, LightCache, sce->eevee.light_cache_data);
1754     write_lightcache(writer, sce->eevee.light_cache_data);
1755   }
1756 
1757   write_view3dshading(writer, &sce->display.shading);
1758 
1759   /* Freed on doversion. */
1760   BLI_assert(sce->layer_properties == NULL);
1761 }
1762 
write_wm_xr_data(BlendWriter * writer,wmXrData * xr_data)1763 static void write_wm_xr_data(BlendWriter *writer, wmXrData *xr_data)
1764 {
1765   write_view3dshading(writer, &xr_data->session_settings.shading);
1766 }
1767 
write_region(BlendWriter * writer,ARegion * region,int spacetype)1768 static void write_region(BlendWriter *writer, ARegion *region, int spacetype)
1769 {
1770   BLO_write_struct(writer, ARegion, region);
1771 
1772   if (region->regiondata) {
1773     if (region->flag & RGN_FLAG_TEMP_REGIONDATA) {
1774       return;
1775     }
1776 
1777     switch (spacetype) {
1778       case SPACE_VIEW3D:
1779         if (region->regiontype == RGN_TYPE_WINDOW) {
1780           RegionView3D *rv3d = region->regiondata;
1781           BLO_write_struct(writer, RegionView3D, rv3d);
1782 
1783           if (rv3d->localvd) {
1784             BLO_write_struct(writer, RegionView3D, rv3d->localvd);
1785           }
1786           if (rv3d->clipbb) {
1787             BLO_write_struct(writer, BoundBox, rv3d->clipbb);
1788           }
1789         }
1790         else {
1791           printf("regiondata write missing!\n");
1792         }
1793         break;
1794       default:
1795         printf("regiondata write missing!\n");
1796     }
1797   }
1798 }
1799 
write_uilist(BlendWriter * writer,uiList * ui_list)1800 static void write_uilist(BlendWriter *writer, uiList *ui_list)
1801 {
1802   BLO_write_struct(writer, uiList, ui_list);
1803 
1804   if (ui_list->properties) {
1805     IDP_BlendWrite(writer, ui_list->properties);
1806   }
1807 }
1808 
write_space_outliner(BlendWriter * writer,SpaceOutliner * space_outliner)1809 static void write_space_outliner(BlendWriter *writer, SpaceOutliner *space_outliner)
1810 {
1811   BLI_mempool *ts = space_outliner->treestore;
1812 
1813   if (ts) {
1814     SpaceOutliner space_outliner_flat = *space_outliner;
1815 
1816     int elems = BLI_mempool_len(ts);
1817     /* linearize mempool to array */
1818     TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL;
1819 
1820     if (data) {
1821       /* In this block we use the memory location of the treestore
1822        * but _not_ its data, the addresses in this case are UUID's,
1823        * since we can't rely on malloc giving us different values each time.
1824        */
1825       TreeStore ts_flat = {0};
1826 
1827       /* we know the treestore is at least as big as a pointer,
1828        * so offsetting works to give us a UUID. */
1829       void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *));
1830 
1831       ts_flat.usedelem = elems;
1832       ts_flat.totelem = elems;
1833       ts_flat.data = data_addr;
1834 
1835       BLO_write_struct(writer, SpaceOutliner, space_outliner);
1836 
1837       BLO_write_struct_at_address(writer, TreeStore, ts, &ts_flat);
1838       BLO_write_struct_array_at_address(writer, TreeStoreElem, elems, data_addr, data);
1839 
1840       MEM_freeN(data);
1841     }
1842     else {
1843       space_outliner_flat.treestore = NULL;
1844       BLO_write_struct_at_address(writer, SpaceOutliner, space_outliner, &space_outliner_flat);
1845     }
1846   }
1847   else {
1848     BLO_write_struct(writer, SpaceOutliner, space_outliner);
1849   }
1850 }
1851 
write_panel_list(BlendWriter * writer,ListBase * lb)1852 static void write_panel_list(BlendWriter *writer, ListBase *lb)
1853 {
1854   LISTBASE_FOREACH (Panel *, panel, lb) {
1855     BLO_write_struct(writer, Panel, panel);
1856     write_panel_list(writer, &panel->children);
1857   }
1858 }
1859 
write_area_regions(BlendWriter * writer,ScrArea * area)1860 static void write_area_regions(BlendWriter *writer, ScrArea *area)
1861 {
1862   LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1863     write_region(writer, region, area->spacetype);
1864     write_panel_list(writer, &region->panels);
1865 
1866     LISTBASE_FOREACH (PanelCategoryStack *, pc_act, &region->panels_category_active) {
1867       BLO_write_struct(writer, PanelCategoryStack, pc_act);
1868     }
1869 
1870     LISTBASE_FOREACH (uiList *, ui_list, &region->ui_lists) {
1871       write_uilist(writer, ui_list);
1872     }
1873 
1874     LISTBASE_FOREACH (uiPreview *, ui_preview, &region->ui_previews) {
1875       BLO_write_struct(writer, uiPreview, ui_preview);
1876     }
1877   }
1878 
1879   LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
1880     LISTBASE_FOREACH (ARegion *, region, &sl->regionbase) {
1881       write_region(writer, region, sl->spacetype);
1882     }
1883 
1884     if (sl->spacetype == SPACE_VIEW3D) {
1885       View3D *v3d = (View3D *)sl;
1886       BLO_write_struct(writer, View3D, v3d);
1887 
1888       if (v3d->localvd) {
1889         BLO_write_struct(writer, View3D, v3d->localvd);
1890       }
1891 
1892       write_view3dshading(writer, &v3d->shading);
1893     }
1894     else if (sl->spacetype == SPACE_GRAPH) {
1895       SpaceGraph *sipo = (SpaceGraph *)sl;
1896       ListBase tmpGhosts = sipo->runtime.ghost_curves;
1897 
1898       /* temporarily disable ghost curves when saving */
1899       BLI_listbase_clear(&sipo->runtime.ghost_curves);
1900 
1901       BLO_write_struct(writer, SpaceGraph, sl);
1902       if (sipo->ads) {
1903         BLO_write_struct(writer, bDopeSheet, sipo->ads);
1904       }
1905 
1906       /* reenable ghost curves */
1907       sipo->runtime.ghost_curves = tmpGhosts;
1908     }
1909     else if (sl->spacetype == SPACE_PROPERTIES) {
1910       BLO_write_struct(writer, SpaceProperties, sl);
1911     }
1912     else if (sl->spacetype == SPACE_FILE) {
1913       SpaceFile *sfile = (SpaceFile *)sl;
1914 
1915       BLO_write_struct(writer, SpaceFile, sl);
1916       if (sfile->params) {
1917         BLO_write_struct(writer, FileSelectParams, sfile->params);
1918       }
1919     }
1920     else if (sl->spacetype == SPACE_SEQ) {
1921       BLO_write_struct(writer, SpaceSeq, sl);
1922     }
1923     else if (sl->spacetype == SPACE_OUTLINER) {
1924       SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
1925       write_space_outliner(writer, space_outliner);
1926     }
1927     else if (sl->spacetype == SPACE_IMAGE) {
1928       BLO_write_struct(writer, SpaceImage, sl);
1929     }
1930     else if (sl->spacetype == SPACE_TEXT) {
1931       BLO_write_struct(writer, SpaceText, sl);
1932     }
1933     else if (sl->spacetype == SPACE_SCRIPT) {
1934       SpaceScript *scr = (SpaceScript *)sl;
1935       scr->but_refs = NULL;
1936       BLO_write_struct(writer, SpaceScript, sl);
1937     }
1938     else if (sl->spacetype == SPACE_ACTION) {
1939       BLO_write_struct(writer, SpaceAction, sl);
1940     }
1941     else if (sl->spacetype == SPACE_NLA) {
1942       SpaceNla *snla = (SpaceNla *)sl;
1943 
1944       BLO_write_struct(writer, SpaceNla, snla);
1945       if (snla->ads) {
1946         BLO_write_struct(writer, bDopeSheet, snla->ads);
1947       }
1948     }
1949     else if (sl->spacetype == SPACE_NODE) {
1950       SpaceNode *snode = (SpaceNode *)sl;
1951       BLO_write_struct(writer, SpaceNode, snode);
1952 
1953       LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
1954         BLO_write_struct(writer, bNodeTreePath, path);
1955       }
1956     }
1957     else if (sl->spacetype == SPACE_CONSOLE) {
1958       SpaceConsole *con = (SpaceConsole *)sl;
1959 
1960       LISTBASE_FOREACH (ConsoleLine *, cl, &con->history) {
1961         /* 'len_alloc' is invalid on write, set from 'len' on read */
1962         BLO_write_struct(writer, ConsoleLine, cl);
1963         BLO_write_raw(writer, (size_t)cl->len + 1, cl->line);
1964       }
1965       BLO_write_struct(writer, SpaceConsole, sl);
1966     }
1967 #ifdef WITH_GLOBAL_AREA_WRITING
1968     else if (sl->spacetype == SPACE_TOPBAR) {
1969       BLO_write_struct(writer, SpaceTopBar, sl);
1970     }
1971     else if (sl->spacetype == SPACE_STATUSBAR) {
1972       BLO_write_struct(writer, SpaceStatusBar, sl);
1973     }
1974 #endif
1975     else if (sl->spacetype == SPACE_USERPREF) {
1976       BLO_write_struct(writer, SpaceUserPref, sl);
1977     }
1978     else if (sl->spacetype == SPACE_CLIP) {
1979       BLO_write_struct(writer, SpaceClip, sl);
1980     }
1981     else if (sl->spacetype == SPACE_INFO) {
1982       BLO_write_struct(writer, SpaceInfo, sl);
1983     }
1984   }
1985 }
1986 
write_area_map(BlendWriter * writer,ScrAreaMap * area_map)1987 static void write_area_map(BlendWriter *writer, ScrAreaMap *area_map)
1988 {
1989   BLO_write_struct_list(writer, ScrVert, &area_map->vertbase);
1990   BLO_write_struct_list(writer, ScrEdge, &area_map->edgebase);
1991   LISTBASE_FOREACH (ScrArea *, area, &area_map->areabase) {
1992     area->butspacetype = area->spacetype; /* Just for compatibility, will be reset below. */
1993 
1994     BLO_write_struct(writer, ScrArea, area);
1995 
1996 #ifdef WITH_GLOBAL_AREA_WRITING
1997     BLO_write_struct(writer, ScrGlobalAreaData, area->global);
1998 #endif
1999 
2000     write_area_regions(writer, area);
2001 
2002     area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */
2003   }
2004 }
2005 
write_windowmanager(BlendWriter * writer,wmWindowManager * wm,const void * id_address)2006 static void write_windowmanager(BlendWriter *writer, wmWindowManager *wm, const void *id_address)
2007 {
2008   BLO_write_id_struct(writer, wmWindowManager, id_address, &wm->id);
2009   BKE_id_blend_write(writer, &wm->id);
2010   write_wm_xr_data(writer, &wm->xr);
2011 
2012   LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2013 #ifndef WITH_GLOBAL_AREA_WRITING
2014     /* Don't write global areas yet, while we make changes to them. */
2015     ScrAreaMap global_areas = win->global_areas;
2016     memset(&win->global_areas, 0, sizeof(win->global_areas));
2017 #endif
2018 
2019     /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
2020     win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
2021 
2022     BLO_write_struct(writer, wmWindow, win);
2023     BLO_write_struct(writer, WorkSpaceInstanceHook, win->workspace_hook);
2024     BLO_write_struct(writer, Stereo3dFormat, win->stereo3d_format);
2025 
2026 #ifdef WITH_GLOBAL_AREA_WRITING
2027     write_area_map(writer, &win->global_areas);
2028 #else
2029     win->global_areas = global_areas;
2030 #endif
2031 
2032     /* data is written, clear deprecated data again */
2033     win->screen = NULL;
2034   }
2035 }
2036 
write_screen(BlendWriter * writer,bScreen * screen,const void * id_address)2037 static void write_screen(BlendWriter *writer, bScreen *screen, const void *id_address)
2038 {
2039   /* Screens are reference counted, only saved if used by a workspace. */
2040   if (screen->id.us > 0 || BLO_write_is_undo(writer)) {
2041     /* write LibData */
2042     /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
2043     writestruct_at_address(writer->wd, ID_SCRN, bScreen, 1, id_address, screen);
2044     BKE_id_blend_write(writer, &screen->id);
2045 
2046     BKE_previewimg_blend_write(writer, screen->preview);
2047 
2048     /* direct data */
2049     write_area_map(writer, AREAMAP_FROM_SCREEN(screen));
2050   }
2051 }
2052 
write_workspace(BlendWriter * writer,WorkSpace * workspace,const void * id_address)2053 static void write_workspace(BlendWriter *writer, WorkSpace *workspace, const void *id_address)
2054 {
2055   BLO_write_id_struct(writer, WorkSpace, id_address, &workspace->id);
2056   BKE_id_blend_write(writer, &workspace->id);
2057   BLO_write_struct_list(writer, WorkSpaceLayout, &workspace->layouts);
2058   BLO_write_struct_list(writer, WorkSpaceDataRelation, &workspace->hook_layout_relations);
2059   BLO_write_struct_list(writer, wmOwnerID, &workspace->owner_ids);
2060   BLO_write_struct_list(writer, bToolRef, &workspace->tools);
2061   LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
2062     if (tref->properties) {
2063       IDP_BlendWrite(writer, tref->properties);
2064     }
2065   }
2066 }
2067 
2068 /* Keep it last of write_foodata functions. */
write_libraries(WriteData * wd,Main * main)2069 static void write_libraries(WriteData *wd, Main *main)
2070 {
2071   ListBase *lbarray[MAX_LIBARRAY];
2072   ID *id;
2073   int a, tot;
2074   bool found_one;
2075 
2076   for (; main; main = main->next) {
2077     a = tot = set_listbasepointers(main, lbarray);
2078 
2079     /* test: is lib being used */
2080     if (main->curlib && main->curlib->packedfile) {
2081       found_one = true;
2082     }
2083     else if (wd->use_memfile) {
2084       /* When writing undo step we always write all existing libraries, makes reading undo step
2085        * much easier when dealing with purely indirectly used libraries. */
2086       found_one = true;
2087     }
2088     else {
2089       found_one = false;
2090       while (!found_one && tot--) {
2091         for (id = lbarray[tot]->first; id; id = id->next) {
2092           if (id->us > 0 &&
2093               ((id->tag & LIB_TAG_EXTERN) ||
2094                ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
2095             found_one = true;
2096             break;
2097           }
2098         }
2099       }
2100     }
2101 
2102     /* To be able to restore 'quit.blend' and temp saves,
2103      * the packed blend has to be in undo buffers... */
2104     /* XXX needs rethink, just like save UI in undo files now -
2105      * would be nice to append things only for the 'quit.blend' and temp saves. */
2106     if (found_one) {
2107       /* Not overridable. */
2108 
2109       BlendWriter writer = {wd};
2110       writestruct(wd, ID_LI, Library, 1, main->curlib);
2111       BKE_id_blend_write(&writer, &main->curlib->id);
2112 
2113       if (main->curlib->packedfile) {
2114         BKE_packedfile_blend_write(&writer, main->curlib->packedfile);
2115         if (wd->use_memfile == false) {
2116           printf("write packed .blend: %s\n", main->curlib->filepath);
2117         }
2118       }
2119 
2120       /* Write link placeholders for all direct linked IDs. */
2121       while (a--) {
2122         for (id = lbarray[a]->first; id; id = id->next) {
2123           if (id->us > 0 &&
2124               ((id->tag & LIB_TAG_EXTERN) ||
2125                ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
2126             if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
2127               printf(
2128                   "ERROR: write file: data-block '%s' from lib '%s' is not linkable "
2129                   "but is flagged as directly linked",
2130                   id->name,
2131                   main->curlib->filepath_abs);
2132               BLI_assert(0);
2133             }
2134             writestruct(wd, ID_LINK_PLACEHOLDER, ID, 1, id);
2135           }
2136         }
2137       }
2138     }
2139   }
2140 
2141   mywrite_flush(wd);
2142 }
2143 
2144 /* context is usually defined by WM, two cases where no WM is available:
2145  * - for forward compatibility, curscreen has to be saved
2146  * - for undofile, curscene needs to be saved */
write_global(WriteData * wd,int fileflags,Main * mainvar)2147 static void write_global(WriteData *wd, int fileflags, Main *mainvar)
2148 {
2149   const bool is_undo = wd->use_memfile;
2150   FileGlobal fg;
2151   bScreen *screen;
2152   Scene *scene;
2153   ViewLayer *view_layer;
2154   char subvstr[8];
2155 
2156   /* prevent mem checkers from complaining */
2157   memset(fg._pad, 0, sizeof(fg._pad));
2158   memset(fg.filename, 0, sizeof(fg.filename));
2159   memset(fg.build_hash, 0, sizeof(fg.build_hash));
2160   fg._pad1 = NULL;
2161 
2162   current_screen_compat(mainvar, is_undo, &screen, &scene, &view_layer);
2163 
2164   /* XXX still remap G */
2165   fg.curscreen = screen;
2166   fg.curscene = scene;
2167   fg.cur_view_layer = view_layer;
2168 
2169   /* prevent to save this, is not good convention, and feature with concerns... */
2170   fg.fileflags = (fileflags & ~G_FILE_FLAG_ALL_RUNTIME);
2171 
2172   fg.globalf = G.f;
2173   BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
2174   sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
2175   memcpy(fg.subvstr, subvstr, 4);
2176 
2177   fg.subversion = BLENDER_FILE_SUBVERSION;
2178   fg.minversion = BLENDER_FILE_MIN_VERSION;
2179   fg.minsubversion = BLENDER_FILE_MIN_SUBVERSION;
2180 #ifdef WITH_BUILDINFO
2181   {
2182     extern unsigned long build_commit_timestamp;
2183     extern char build_hash[];
2184     /* TODO(sergey): Add branch name to file as well? */
2185     fg.build_commit_timestamp = build_commit_timestamp;
2186     BLI_strncpy(fg.build_hash, build_hash, sizeof(fg.build_hash));
2187   }
2188 #else
2189   fg.build_commit_timestamp = 0;
2190   BLI_strncpy(fg.build_hash, "unknown", sizeof(fg.build_hash));
2191 #endif
2192   writestruct(wd, GLOB, FileGlobal, 1, &fg);
2193 }
2194 
2195 /* preview image, first 2 values are width and height
2196  * second are an RGBA image (uchar)
2197  * note, this uses 'TEST' since new types will segfault on file load for older blender versions.
2198  */
write_thumb(WriteData * wd,const BlendThumbnail * thumb)2199 static void write_thumb(WriteData *wd, const BlendThumbnail *thumb)
2200 {
2201   if (thumb) {
2202     writedata(wd, TEST, BLEN_THUMB_MEMSIZE_FILE(thumb->width, thumb->height), thumb);
2203   }
2204 }
2205 
2206 /** \} */
2207 
2208 /* -------------------------------------------------------------------- */
2209 /** \name File Writing (Private)
2210  * \{ */
2211 
2212 /* if MemFile * there's filesave to memory */
write_file_handle(Main * mainvar,WriteWrap * ww,MemFile * compare,MemFile * current,int write_flags,bool use_userdef,const BlendThumbnail * thumb)2213 static bool write_file_handle(Main *mainvar,
2214                               WriteWrap *ww,
2215                               MemFile *compare,
2216                               MemFile *current,
2217                               int write_flags,
2218                               bool use_userdef,
2219                               const BlendThumbnail *thumb)
2220 {
2221   BHead bhead;
2222   ListBase mainlist;
2223   char buf[16];
2224   WriteData *wd;
2225 
2226   blo_split_main(&mainlist, mainvar);
2227 
2228   wd = mywrite_begin(ww, compare, current);
2229   BlendWriter writer = {wd};
2230 
2231   sprintf(buf,
2232           "BLENDER%c%c%.3d",
2233           (sizeof(void *) == 8) ? '-' : '_',
2234           (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v',
2235           BLENDER_FILE_VERSION);
2236 
2237   mywrite(wd, buf, 12);
2238 
2239   write_renderinfo(wd, mainvar);
2240   write_thumb(wd, thumb);
2241   write_global(wd, write_flags, mainvar);
2242 
2243   /* The windowmanager and screen often change,
2244    * avoid thumbnail detecting changes because of this. */
2245   mywrite_flush(wd);
2246 
2247   OverrideLibraryStorage *override_storage = wd->use_memfile ?
2248                                                  NULL :
2249                                                  BKE_lib_override_library_operations_store_init();
2250 
2251 #define ID_BUFFER_STATIC_SIZE 8192
2252   /* This outer loop allows to save first data-blocks from real mainvar,
2253    * then the temp ones from override process,
2254    * if needed, without duplicating whole code. */
2255   Main *bmain = mainvar;
2256   do {
2257     ListBase *lbarray[MAX_LIBARRAY];
2258     int a = set_listbasepointers(bmain, lbarray);
2259     while (a--) {
2260       ID *id = lbarray[a]->first;
2261 
2262       if (id == NULL || GS(id->name) == ID_LI) {
2263         continue; /* Libraries are handled separately below. */
2264       }
2265 
2266       char id_buffer_static[ID_BUFFER_STATIC_SIZE];
2267       void *id_buffer = id_buffer_static;
2268       const size_t idtype_struct_size = BKE_idtype_get_info_from_id(id)->struct_size;
2269       if (idtype_struct_size > ID_BUFFER_STATIC_SIZE) {
2270         BLI_assert(0);
2271         id_buffer = MEM_mallocN(idtype_struct_size, __func__);
2272       }
2273 
2274       for (; id; id = id->next) {
2275         /* We should never attempt to write non-regular IDs
2276          * (i.e. all kind of temp/runtime ones). */
2277         BLI_assert(
2278             (id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
2279 
2280         const bool do_override = !ELEM(override_storage, NULL, bmain) &&
2281                                  ID_IS_OVERRIDE_LIBRARY_REAL(id);
2282 
2283         if (do_override) {
2284           BKE_lib_override_library_operations_store_start(bmain, override_storage, id);
2285         }
2286 
2287         if (wd->use_memfile) {
2288           /* Record the changes that happened up to this undo push in
2289            * recalc_up_to_undo_push, and clear recalc_after_undo_push again
2290            * to start accumulating for the next undo push. */
2291           id->recalc_up_to_undo_push = id->recalc_after_undo_push;
2292           id->recalc_after_undo_push = 0;
2293 
2294           bNodeTree *nodetree = ntreeFromID(id);
2295           if (nodetree != NULL) {
2296             nodetree->id.recalc_up_to_undo_push = nodetree->id.recalc_after_undo_push;
2297             nodetree->id.recalc_after_undo_push = 0;
2298           }
2299           if (GS(id->name) == ID_SCE) {
2300             Scene *scene = (Scene *)id;
2301             if (scene->master_collection != NULL) {
2302               scene->master_collection->id.recalc_up_to_undo_push =
2303                   scene->master_collection->id.recalc_after_undo_push;
2304               scene->master_collection->id.recalc_after_undo_push = 0;
2305             }
2306           }
2307         }
2308 
2309         mywrite_id_begin(wd, id);
2310 
2311         memcpy(id_buffer, id, idtype_struct_size);
2312 
2313         ((ID *)id_buffer)->tag = 0;
2314         /* Those listbase data change every time we add/remove an ID, and also often when
2315          * renaming one (due to re-sorting). This avoids generating a lot of false 'is changed'
2316          * detections between undo steps. */
2317         ((ID *)id_buffer)->prev = NULL;
2318         ((ID *)id_buffer)->next = NULL;
2319 
2320         const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
2321         if (id_type->blend_write != NULL) {
2322           id_type->blend_write(&writer, (ID *)id_buffer, id);
2323         }
2324 
2325         switch ((ID_Type)GS(id->name)) {
2326           case ID_WM:
2327             write_windowmanager(&writer, (wmWindowManager *)id_buffer, id);
2328             break;
2329           case ID_WS:
2330             write_workspace(&writer, (WorkSpace *)id_buffer, id);
2331             break;
2332           case ID_SCR:
2333             write_screen(&writer, (bScreen *)id_buffer, id);
2334             break;
2335           case ID_SCE:
2336             write_scene(&writer, (Scene *)id_buffer, id);
2337             break;
2338           case ID_GR:
2339             write_collection(&writer, (Collection *)id_buffer, id);
2340             break;
2341           case ID_OB:
2342             write_object(&writer, (Object *)id_buffer, id);
2343             break;
2344           case ID_PA:
2345             write_particlesettings(&writer, (ParticleSettings *)id_buffer, id);
2346             break;
2347           case ID_ME:
2348           case ID_LT:
2349           case ID_AC:
2350           case ID_NT:
2351           case ID_LS:
2352           case ID_TXT:
2353           case ID_VF:
2354           case ID_MC:
2355           case ID_PC:
2356           case ID_PAL:
2357           case ID_BR:
2358           case ID_IM:
2359           case ID_LA:
2360           case ID_MA:
2361           case ID_MB:
2362           case ID_CU:
2363           case ID_CA:
2364           case ID_WO:
2365           case ID_MSK:
2366           case ID_SPK:
2367           case ID_AR:
2368           case ID_LP:
2369           case ID_KE:
2370           case ID_TE:
2371           case ID_GD:
2372           case ID_HA:
2373           case ID_PT:
2374           case ID_VO:
2375           case ID_SIM:
2376           case ID_SO:
2377           case ID_CF:
2378             /* Do nothing, handled in IDTypeInfo callback. */
2379             break;
2380           case ID_LI:
2381             /* Do nothing, handled below - and should never be reached. */
2382             BLI_assert(0);
2383             break;
2384           case ID_IP:
2385             /* Do nothing, deprecated. */
2386             break;
2387           default:
2388             /* Should never be reached. */
2389             BLI_assert(0);
2390             break;
2391         }
2392 
2393         if (do_override) {
2394           BKE_lib_override_library_operations_store_end(override_storage, id);
2395         }
2396 
2397         mywrite_id_end(wd, id);
2398       }
2399 
2400       if (id_buffer != id_buffer_static) {
2401         MEM_SAFE_FREE(id_buffer);
2402       }
2403 
2404       mywrite_flush(wd);
2405     }
2406   } while ((bmain != override_storage) && (bmain = override_storage));
2407 
2408   if (override_storage) {
2409     BKE_lib_override_library_operations_store_finalize(override_storage);
2410     override_storage = NULL;
2411   }
2412 
2413   /* Special handling, operating over split Mains... */
2414   write_libraries(wd, mainvar->next);
2415 
2416   /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
2417   mywrite_flush(wd);
2418 
2419   if (use_userdef) {
2420     write_userdef(&writer, &U);
2421   }
2422 
2423   /* Write DNA last, because (to be implemented) test for which structs are written.
2424    *
2425    * Note that we *borrow* the pointer to 'DNAstr',
2426    * so writing each time uses the same address and doesn't cause unnecessary undo overhead. */
2427   writedata(wd, DNA1, (size_t)wd->sdna->data_len, wd->sdna->data);
2428 
2429   /* end of file */
2430   memset(&bhead, 0, sizeof(BHead));
2431   bhead.code = ENDB;
2432   mywrite(wd, &bhead, sizeof(BHead));
2433 
2434   blo_join_main(&mainlist);
2435 
2436   return mywrite_end(wd);
2437 }
2438 
2439 /* do reverse file history: .blend1 -> .blend2, .blend -> .blend1 */
2440 /* return: success(0), failure(1) */
do_history(const char * name,ReportList * reports)2441 static bool do_history(const char *name, ReportList *reports)
2442 {
2443   char tempname1[FILE_MAX], tempname2[FILE_MAX];
2444   int hisnr = U.versions;
2445 
2446   if (U.versions == 0) {
2447     return 0;
2448   }
2449 
2450   if (strlen(name) < 2) {
2451     BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short");
2452     return 1;
2453   }
2454 
2455   while (hisnr > 1) {
2456     BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr - 1);
2457     if (BLI_exists(tempname1)) {
2458       BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
2459 
2460       if (BLI_rename(tempname1, tempname2)) {
2461         BKE_report(reports, RPT_ERROR, "Unable to make version backup");
2462         return true;
2463       }
2464     }
2465     hisnr--;
2466   }
2467 
2468   /* is needed when hisnr==1 */
2469   if (BLI_exists(name)) {
2470     BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr);
2471 
2472     if (BLI_rename(name, tempname1)) {
2473       BKE_report(reports, RPT_ERROR, "Unable to make version backup");
2474       return true;
2475     }
2476   }
2477 
2478   return 0;
2479 }
2480 
2481 /** \} */
2482 
2483 /* -------------------------------------------------------------------- */
2484 /** \name File Writing (Public)
2485  * \{ */
2486 
2487 /**
2488  * \return Success.
2489  */
BLO_write_file(Main * mainvar,const char * filepath,const int write_flags,const struct BlendFileWriteParams * params,ReportList * reports)2490 bool BLO_write_file(Main *mainvar,
2491                     const char *filepath,
2492                     const int write_flags,
2493                     const struct BlendFileWriteParams *params,
2494                     ReportList *reports)
2495 {
2496   char tempname[FILE_MAX + 1];
2497   eWriteWrapType ww_type;
2498   WriteWrap ww;
2499 
2500   eBLO_WritePathRemap remap_mode = params->remap_mode;
2501   const bool use_save_versions = params->use_save_versions;
2502   const bool use_save_as_copy = params->use_save_as_copy;
2503   const bool use_userdef = params->use_userdef;
2504   const BlendThumbnail *thumb = params->thumb;
2505 
2506   /* path backup/restore */
2507   void *path_list_backup = NULL;
2508   const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
2509 
2510   if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
2511     BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
2512     BLO_main_validate_libraries(mainvar, reports);
2513     BLO_main_validate_shapekeys(mainvar, reports);
2514   }
2515 
2516   /* open temporary file, so we preserve the original in case we crash */
2517   BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
2518 
2519   if (write_flags & G_FILE_COMPRESS) {
2520     ww_type = WW_WRAP_ZLIB;
2521   }
2522   else {
2523     ww_type = WW_WRAP_NONE;
2524   }
2525 
2526   ww_handle_init(ww_type, &ww);
2527 
2528   if (ww.open(&ww, tempname) == false) {
2529     BKE_reportf(
2530         reports, RPT_ERROR, "Cannot open file %s for writing: %s", tempname, strerror(errno));
2531     return 0;
2532   }
2533 
2534   /* Remapping of relative paths to new file location. */
2535   if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
2536 
2537     if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
2538       /* Make all relative as none of the existing paths can be relative in an unsaved document.
2539        */
2540       if (G.relbase_valid == false) {
2541         remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL;
2542       }
2543     }
2544 
2545     char dir_src[FILE_MAX];
2546     char dir_dst[FILE_MAX];
2547     BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src));
2548     BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
2549 
2550     /* Just in case there is some subtle difference. */
2551     BLI_path_normalize(mainvar->name, dir_dst);
2552     BLI_path_normalize(mainvar->name, dir_src);
2553 
2554     /* Only for relative, not relative-all, as this means making existing paths relative. */
2555     if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
2556       if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
2557         /* Saved to same path. Nothing to do. */
2558         remap_mode = BLO_WRITE_PATH_REMAP_NONE;
2559       }
2560     }
2561     else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
2562       if (G.relbase_valid == false) {
2563         /* Unsaved, all paths are absolute.Even if the user manages to set a relative path,
2564          * there is no base-path that can be used to make it absolute. */
2565         remap_mode = BLO_WRITE_PATH_REMAP_NONE;
2566       }
2567     }
2568 
2569     if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
2570       /* Check if we need to backup and restore paths. */
2571       if (UNLIKELY(use_save_as_copy)) {
2572         path_list_backup = BKE_bpath_list_backup(mainvar, path_list_flag);
2573       }
2574 
2575       switch (remap_mode) {
2576         case BLO_WRITE_PATH_REMAP_RELATIVE:
2577           /* Saved, make relative paths relative to new location (if possible). */
2578           BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL);
2579           break;
2580         case BLO_WRITE_PATH_REMAP_RELATIVE_ALL:
2581           /* Make all relative (when requested or unsaved). */
2582           BKE_bpath_relative_convert(mainvar, dir_dst, NULL);
2583           break;
2584         case BLO_WRITE_PATH_REMAP_ABSOLUTE:
2585           /* Make all absolute (when requested or unsaved). */
2586           BKE_bpath_absolute_convert(mainvar, dir_src, NULL);
2587           break;
2588         case BLO_WRITE_PATH_REMAP_NONE:
2589           BLI_assert(0); /* Unreachable. */
2590           break;
2591       }
2592     }
2593   }
2594 
2595   /* actual file writing */
2596   const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, use_userdef, thumb);
2597 
2598   ww.close(&ww);
2599 
2600   if (UNLIKELY(path_list_backup)) {
2601     BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup);
2602     BKE_bpath_list_free(path_list_backup);
2603   }
2604 
2605   if (err) {
2606     BKE_report(reports, RPT_ERROR, strerror(errno));
2607     remove(tempname);
2608 
2609     return 0;
2610   }
2611 
2612   /* file save to temporary file was successful */
2613   /* now do reverse file history (move .blend1 -> .blend2, .blend -> .blend1) */
2614   if (use_save_versions) {
2615     const bool err_hist = do_history(filepath, reports);
2616     if (err_hist) {
2617       BKE_report(reports, RPT_ERROR, "Version backup failed (file saved with @)");
2618       return 0;
2619     }
2620   }
2621 
2622   if (BLI_rename(tempname, filepath) != 0) {
2623     BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
2624     return 0;
2625   }
2626 
2627   if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
2628     BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* save to disk");
2629     BLO_main_validate_libraries(mainvar, reports);
2630   }
2631 
2632   return 1;
2633 }
2634 
2635 /**
2636  * \return Success.
2637  */
BLO_write_file_mem(Main * mainvar,MemFile * compare,MemFile * current,int write_flags)2638 bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
2639 {
2640   bool use_userdef = false;
2641 
2642   const bool err = write_file_handle(
2643       mainvar, NULL, compare, current, write_flags, use_userdef, NULL);
2644 
2645   return (err == 0);
2646 }
2647 
BLO_write_raw(BlendWriter * writer,size_t size_in_bytes,const void * data_ptr)2648 void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr)
2649 {
2650   writedata(writer->wd, DATA, size_in_bytes, data_ptr);
2651 }
2652 
BLO_write_struct_by_name(BlendWriter * writer,const char * struct_name,const void * data_ptr)2653 void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
2654 {
2655   BLO_write_struct_array_by_name(writer, struct_name, 1, data_ptr);
2656 }
2657 
BLO_write_struct_array_by_name(BlendWriter * writer,const char * struct_name,int array_size,const void * data_ptr)2658 void BLO_write_struct_array_by_name(BlendWriter *writer,
2659                                     const char *struct_name,
2660                                     int array_size,
2661                                     const void *data_ptr)
2662 {
2663   int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
2664   if (UNLIKELY(struct_id == -1)) {
2665     printf("error: can't find SDNA code <%s>\n", struct_name);
2666     return;
2667   }
2668   BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
2669 }
2670 
BLO_write_struct_by_id(BlendWriter * writer,int struct_id,const void * data_ptr)2671 void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr)
2672 {
2673   writestruct_nr(writer->wd, DATA, struct_id, 1, data_ptr);
2674 }
2675 
BLO_write_struct_at_address_by_id(BlendWriter * writer,int struct_id,const void * address,const void * data_ptr)2676 void BLO_write_struct_at_address_by_id(BlendWriter *writer,
2677                                        int struct_id,
2678                                        const void *address,
2679                                        const void *data_ptr)
2680 {
2681   writestruct_at_address_nr(writer->wd, DATA, struct_id, 1, address, data_ptr);
2682 }
2683 
BLO_write_struct_array_by_id(BlendWriter * writer,int struct_id,int array_size,const void * data_ptr)2684 void BLO_write_struct_array_by_id(BlendWriter *writer,
2685                                   int struct_id,
2686                                   int array_size,
2687                                   const void *data_ptr)
2688 {
2689   writestruct_nr(writer->wd, DATA, struct_id, array_size, data_ptr);
2690 }
2691 
BLO_write_struct_array_at_address_by_id(BlendWriter * writer,int struct_id,int array_size,const void * address,const void * data_ptr)2692 void BLO_write_struct_array_at_address_by_id(
2693     BlendWriter *writer, int struct_id, int array_size, const void *address, const void *data_ptr)
2694 {
2695   writestruct_at_address_nr(writer->wd, DATA, struct_id, array_size, address, data_ptr);
2696 }
2697 
BLO_write_struct_list_by_id(BlendWriter * writer,int struct_id,ListBase * list)2698 void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, ListBase *list)
2699 {
2700   writelist_nr(writer->wd, DATA, struct_id, list);
2701 }
2702 
BLO_write_struct_list_by_name(BlendWriter * writer,const char * struct_name,ListBase * list)2703 void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name, ListBase *list)
2704 {
2705   int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
2706   if (UNLIKELY(struct_id == -1)) {
2707     printf("error: can't find SDNA code <%s>\n", struct_name);
2708     return;
2709   }
2710   BLO_write_struct_list_by_id(writer, struct_id, list);
2711 }
2712 
blo_write_id_struct(BlendWriter * writer,int struct_id,const void * id_address,const ID * id)2713 void blo_write_id_struct(BlendWriter *writer, int struct_id, const void *id_address, const ID *id)
2714 {
2715   writestruct_at_address_nr(writer->wd, GS(id->name), struct_id, 1, id_address, id);
2716 }
2717 
BLO_get_struct_id_by_name(BlendWriter * writer,const char * struct_name)2718 int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name)
2719 {
2720   int struct_id = DNA_struct_find_nr(writer->wd->sdna, struct_name);
2721   return struct_id;
2722 }
2723 
BLO_write_int32_array(BlendWriter * writer,uint num,const int32_t * data_ptr)2724 void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr)
2725 {
2726   BLO_write_raw(writer, sizeof(int32_t) * (size_t)num, data_ptr);
2727 }
2728 
BLO_write_uint32_array(BlendWriter * writer,uint num,const uint32_t * data_ptr)2729 void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr)
2730 {
2731   BLO_write_raw(writer, sizeof(uint32_t) * (size_t)num, data_ptr);
2732 }
2733 
BLO_write_float_array(BlendWriter * writer,uint num,const float * data_ptr)2734 void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
2735 {
2736   BLO_write_raw(writer, sizeof(float) * (size_t)num, data_ptr);
2737 }
2738 
BLO_write_pointer_array(BlendWriter * writer,uint num,const void * data_ptr)2739 void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
2740 {
2741   BLO_write_raw(writer, sizeof(void *) * (size_t)num, data_ptr);
2742 }
2743 
BLO_write_float3_array(BlendWriter * writer,uint num,const float * data_ptr)2744 void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
2745 {
2746   BLO_write_raw(writer, sizeof(float[3]) * (size_t)num, data_ptr);
2747 }
2748 
2749 /**
2750  * Write a null terminated string.
2751  */
BLO_write_string(BlendWriter * writer,const char * data_ptr)2752 void BLO_write_string(BlendWriter *writer, const char *data_ptr)
2753 {
2754   if (data_ptr != NULL) {
2755     BLO_write_raw(writer, strlen(data_ptr) + 1, data_ptr);
2756   }
2757 }
2758 
2759 /**
2760  * Sometimes different data is written depending on whether the file is saved to disk or used for
2761  * undo. This function returns true when the current file-writing is done for undo.
2762  */
BLO_write_is_undo(BlendWriter * writer)2763 bool BLO_write_is_undo(BlendWriter *writer)
2764 {
2765   return writer->wd->use_memfile;
2766 }
2767 
2768 /** \} */
2769