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