Fix T69593: Color strip won't update
[blender.git] / source / blender / blenkernel / intern / customdata_file.c
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
17 /** \file
18  * \ingroup bke
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_utildefines.h"
28 #include "BLI_fileops.h"
29 #include "BLI_string.h"
30 #include "BLI_endian_switch.h"
31
32 #include "BKE_customdata_file.h"
33 #include "BKE_global.h"
34
35 /************************* File Format Definitions ***************************/
36
37 #define CDF_ENDIAN_LITTLE 0
38 #define CDF_ENDIAN_BIG 1
39
40 #define CDF_DATA_FLOAT 0
41
42 typedef struct CDataFileHeader {
43   char ID[4];      /* "BCDF" */
44   char endian;     /* little, big */
45   char version;    /* non-compatible versions */
46   char subversion; /* compatible sub versions */
47   char pad;        /* padding */
48
49   int structbytes; /* size of this struct in bytes */
50   int type;        /* image, mesh */
51   int totlayer;    /* number of layers in the file */
52 } CDataFileHeader;
53
54 typedef struct CDataFileImageHeader {
55   int structbytes; /* size of this struct in bytes */
56   int width;       /* image width */
57   int height;      /* image height */
58   int tile_size;   /* tile size (required power of 2) */
59 } CDataFileImageHeader;
60
61 typedef struct CDataFileMeshHeader {
62   int structbytes; /* size of this struct in bytes */
63 } CDataFileMeshHeader;
64
65 struct CDataFileLayer {
66   int structbytes;               /* size of this struct in bytes */
67   int datatype;                  /* only float for now */
68   uint64_t datasize;             /* size of data in layer */
69   int type;                      /* layer type */
70   char name[CDF_LAYER_NAME_MAX]; /* layer name */
71 };
72
73 /**************************** Other Definitions ******************************/
74
75 #define CDF_VERSION 0
76 #define CDF_SUBVERSION 0
77 #define CDF_TILE_SIZE 64
78
79 struct CDataFile {
80   int type;
81
82   CDataFileHeader header;
83   union {
84     CDataFileImageHeader image;
85     CDataFileMeshHeader mesh;
86   } btype;
87
88   CDataFileLayer *layer;
89   int totlayer;
90
91   FILE *readf;
92   FILE *writef;
93   int switchendian;
94   size_t dataoffset;
95 };
96
97 /********************************* Create/Free *******************************/
98
99 static int cdf_endian(void)
100 {
101   if (ENDIAN_ORDER == L_ENDIAN) {
102     return CDF_ENDIAN_LITTLE;
103   }
104   else {
105     return CDF_ENDIAN_BIG;
106   }
107 }
108
109 CDataFile *cdf_create(int type)
110 {
111   CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
112
113   cdf->type = type;
114
115   return cdf;
116 }
117
118 void cdf_free(CDataFile *cdf)
119 {
120   cdf_read_close(cdf);
121   cdf_write_close(cdf);
122
123   if (cdf->layer) {
124     MEM_freeN(cdf->layer);
125   }
126
127   MEM_freeN(cdf);
128 }
129
130 /********************************* Read/Write ********************************/
131
132 static int cdf_read_header(CDataFile *cdf)
133 {
134   CDataFileHeader *header;
135   CDataFileImageHeader *image;
136   CDataFileMeshHeader *mesh;
137   CDataFileLayer *layer;
138   FILE *f = cdf->readf;
139   size_t offset = 0;
140   int a;
141
142   header = &cdf->header;
143
144   if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf)) {
145     return 0;
146   }
147
148   if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0) {
149     return 0;
150   }
151   if (header->version > CDF_VERSION) {
152     return 0;
153   }
154
155   cdf->switchendian = header->endian != cdf_endian();
156   header->endian = cdf_endian();
157
158   if (cdf->switchendian) {
159     BLI_endian_switch_int32(&header->type);
160     BLI_endian_switch_int32(&header->totlayer);
161     BLI_endian_switch_int32(&header->structbytes);
162   }
163
164   if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH)) {
165     return 0;
166   }
167
168   offset += header->structbytes;
169   header->structbytes = sizeof(CDataFileHeader);
170
171   if (fseek(f, offset, SEEK_SET) != 0) {
172     return 0;
173   }
174
175   if (header->type == CDF_TYPE_IMAGE) {
176     image = &cdf->btype.image;
177     if (!fread(image, sizeof(CDataFileImageHeader), 1, f)) {
178       return 0;
179     }
180
181     if (cdf->switchendian) {
182       BLI_endian_switch_int32(&image->width);
183       BLI_endian_switch_int32(&image->height);
184       BLI_endian_switch_int32(&image->tile_size);
185       BLI_endian_switch_int32(&image->structbytes);
186     }
187
188     offset += image->structbytes;
189     image->structbytes = sizeof(CDataFileImageHeader);
190   }
191   else if (header->type == CDF_TYPE_MESH) {
192     mesh = &cdf->btype.mesh;
193     if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
194       return 0;
195     }
196
197     if (cdf->switchendian) {
198       BLI_endian_switch_int32(&mesh->structbytes);
199     }
200
201     offset += mesh->structbytes;
202     mesh->structbytes = sizeof(CDataFileMeshHeader);
203   }
204
205   if (fseek(f, offset, SEEK_SET) != 0) {
206     return 0;
207   }
208
209   cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
210   cdf->totlayer = header->totlayer;
211
212   if (!cdf->layer) {
213     return 0;
214   }
215
216   for (a = 0; a < header->totlayer; a++) {
217     layer = &cdf->layer[a];
218
219     if (!fread(layer, sizeof(CDataFileLayer), 1, f)) {
220       return 0;
221     }
222
223     if (cdf->switchendian) {
224       BLI_endian_switch_int32(&layer->type);
225       BLI_endian_switch_int32(&layer->datatype);
226       BLI_endian_switch_uint64(&layer->datasize);
227       BLI_endian_switch_int32(&layer->structbytes);
228     }
229
230     if (layer->datatype != CDF_DATA_FLOAT) {
231       return 0;
232     }
233
234     offset += layer->structbytes;
235     layer->structbytes = sizeof(CDataFileLayer);
236
237     if (fseek(f, offset, SEEK_SET) != 0) {
238       return 0;
239     }
240   }
241
242   cdf->dataoffset = offset;
243
244   return 1;
245 }
246
247 static int cdf_write_header(CDataFile *cdf)
248 {
249   CDataFileHeader *header;
250   CDataFileImageHeader *image;
251   CDataFileMeshHeader *mesh;
252   CDataFileLayer *layer;
253   FILE *f = cdf->writef;
254   int a;
255
256   header = &cdf->header;
257
258   if (!fwrite(header, sizeof(CDataFileHeader), 1, f)) {
259     return 0;
260   }
261
262   if (header->type == CDF_TYPE_IMAGE) {
263     image = &cdf->btype.image;
264     if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f)) {
265       return 0;
266     }
267   }
268   else if (header->type == CDF_TYPE_MESH) {
269     mesh = &cdf->btype.mesh;
270     if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f)) {
271       return 0;
272     }
273   }
274
275   for (a = 0; a < header->totlayer; a++) {
276     layer = &cdf->layer[a];
277
278     if (!fwrite(layer, sizeof(CDataFileLayer), 1, f)) {
279       return 0;
280     }
281   }
282
283   return 1;
284 }
285
286 bool cdf_read_open(CDataFile *cdf, const char *filename)
287 {
288   FILE *f;
289
290   f = BLI_fopen(filename, "rb");
291   if (!f) {
292     return 0;
293   }
294
295   cdf->readf = f;
296
297   if (!cdf_read_header(cdf)) {
298     cdf_read_close(cdf);
299     return 0;
300   }
301
302   if (cdf->header.type != cdf->type) {
303     cdf_read_close(cdf);
304     return 0;
305   }
306
307   return 1;
308 }
309
310 bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
311 {
312   size_t offset;
313   int a;
314
315   /* seek to right location in file */
316   offset = cdf->dataoffset;
317   for (a = 0; a < cdf->totlayer; a++) {
318     if (&cdf->layer[a] == blay) {
319       break;
320     }
321     else {
322       offset += cdf->layer[a].datasize;
323     }
324   }
325
326   return (fseek(cdf->readf, offset, SEEK_SET) == 0);
327 }
328
329 bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
330 {
331   /* read data */
332   if (!fread(data, size, 1, cdf->readf)) {
333     return 0;
334   }
335
336   /* switch endian if necessary */
337   if (cdf->switchendian) {
338     BLI_endian_switch_float_array(data, size / sizeof(float));
339   }
340
341   return 1;
342 }
343
344 void cdf_read_close(CDataFile *cdf)
345 {
346   if (cdf->readf) {
347     fclose(cdf->readf);
348     cdf->readf = NULL;
349   }
350 }
351
352 bool cdf_write_open(CDataFile *cdf, const char *filename)
353 {
354   CDataFileHeader *header;
355   CDataFileImageHeader *image;
356   CDataFileMeshHeader *mesh;
357   FILE *f;
358
359   f = BLI_fopen(filename, "wb");
360   if (!f) {
361     return 0;
362   }
363
364   cdf->writef = f;
365
366   /* fill header */
367   header = &cdf->header;
368   /* strcpy(, "BCDF"); // terminator out of range */
369   header->ID[0] = 'B';
370   header->ID[1] = 'C';
371   header->ID[2] = 'D';
372   header->ID[3] = 'F';
373   header->endian = cdf_endian();
374   header->version = CDF_VERSION;
375   header->subversion = CDF_SUBVERSION;
376
377   header->structbytes = sizeof(CDataFileHeader);
378   header->type = cdf->type;
379   header->totlayer = cdf->totlayer;
380
381   if (cdf->type == CDF_TYPE_IMAGE) {
382     /* fill image header */
383     image = &cdf->btype.image;
384     image->structbytes = sizeof(CDataFileImageHeader);
385     image->tile_size = CDF_TILE_SIZE;
386   }
387   else if (cdf->type == CDF_TYPE_MESH) {
388     /* fill mesh header */
389     mesh = &cdf->btype.mesh;
390     mesh->structbytes = sizeof(CDataFileMeshHeader);
391   }
392
393   cdf_write_header(cdf);
394
395   return 1;
396 }
397
398 bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
399 {
400   return 1;
401 }
402
403 bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
404 {
405   /* write data */
406   if (!fwrite(data, size, 1, cdf->writef)) {
407     return 0;
408   }
409
410   return 1;
411 }
412
413 void cdf_write_close(CDataFile *cdf)
414 {
415   if (cdf->writef) {
416     fclose(cdf->writef);
417     cdf->writef = NULL;
418   }
419 }
420
421 void cdf_remove(const char *filename)
422 {
423   BLI_delete(filename, false, false);
424 }
425
426 /********************************** Layers ***********************************/
427
428 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
429 {
430   CDataFileLayer *layer;
431   int a;
432
433   for (a = 0; a < cdf->totlayer; a++) {
434     layer = &cdf->layer[a];
435
436     if (layer->type == type && STREQ(layer->name, name)) {
437       return layer;
438     }
439   }
440
441   return NULL;
442 }
443
444 CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
445 {
446   CDataFileLayer *newlayer, *layer;
447
448   /* expand array */
449   newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
450   memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
451   cdf->layer = newlayer;
452
453   cdf->totlayer++;
454
455   /* fill in new layer */
456   layer = &cdf->layer[cdf->totlayer - 1];
457   layer->structbytes = sizeof(CDataFileLayer);
458   layer->datatype = CDF_DATA_FLOAT;
459   layer->datasize = datasize;
460   layer->type = type;
461   BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
462
463   return layer;
464 }