ClangFormat: apply to source, most of intern
[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   else
104     return CDF_ENDIAN_BIG;
105 }
106
107 CDataFile *cdf_create(int type)
108 {
109   CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
110
111   cdf->type = type;
112
113   return cdf;
114 }
115
116 void cdf_free(CDataFile *cdf)
117 {
118   cdf_read_close(cdf);
119   cdf_write_close(cdf);
120
121   if (cdf->layer)
122     MEM_freeN(cdf->layer);
123
124   MEM_freeN(cdf);
125 }
126
127 /********************************* Read/Write ********************************/
128
129 static int cdf_read_header(CDataFile *cdf)
130 {
131   CDataFileHeader *header;
132   CDataFileImageHeader *image;
133   CDataFileMeshHeader *mesh;
134   CDataFileLayer *layer;
135   FILE *f = cdf->readf;
136   size_t offset = 0;
137   int a;
138
139   header = &cdf->header;
140
141   if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf))
142     return 0;
143
144   if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0)
145     return 0;
146   if (header->version > CDF_VERSION)
147     return 0;
148
149   cdf->switchendian = header->endian != cdf_endian();
150   header->endian = cdf_endian();
151
152   if (cdf->switchendian) {
153     BLI_endian_switch_int32(&header->type);
154     BLI_endian_switch_int32(&header->totlayer);
155     BLI_endian_switch_int32(&header->structbytes);
156   }
157
158   if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH))
159     return 0;
160
161   offset += header->structbytes;
162   header->structbytes = sizeof(CDataFileHeader);
163
164   if (fseek(f, offset, SEEK_SET) != 0)
165     return 0;
166
167   if (header->type == CDF_TYPE_IMAGE) {
168     image = &cdf->btype.image;
169     if (!fread(image, sizeof(CDataFileImageHeader), 1, f))
170       return 0;
171
172     if (cdf->switchendian) {
173       BLI_endian_switch_int32(&image->width);
174       BLI_endian_switch_int32(&image->height);
175       BLI_endian_switch_int32(&image->tile_size);
176       BLI_endian_switch_int32(&image->structbytes);
177     }
178
179     offset += image->structbytes;
180     image->structbytes = sizeof(CDataFileImageHeader);
181   }
182   else if (header->type == CDF_TYPE_MESH) {
183     mesh = &cdf->btype.mesh;
184     if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f))
185       return 0;
186
187     if (cdf->switchendian)
188       BLI_endian_switch_int32(&mesh->structbytes);
189
190     offset += mesh->structbytes;
191     mesh->structbytes = sizeof(CDataFileMeshHeader);
192   }
193
194   if (fseek(f, offset, SEEK_SET) != 0)
195     return 0;
196
197   cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
198   cdf->totlayer = header->totlayer;
199
200   if (!cdf->layer) {
201     return 0;
202   }
203
204   for (a = 0; a < header->totlayer; a++) {
205     layer = &cdf->layer[a];
206
207     if (!fread(layer, sizeof(CDataFileLayer), 1, f))
208       return 0;
209
210     if (cdf->switchendian) {
211       BLI_endian_switch_int32(&layer->type);
212       BLI_endian_switch_int32(&layer->datatype);
213       BLI_endian_switch_uint64(&layer->datasize);
214       BLI_endian_switch_int32(&layer->structbytes);
215     }
216
217     if (layer->datatype != CDF_DATA_FLOAT)
218       return 0;
219
220     offset += layer->structbytes;
221     layer->structbytes = sizeof(CDataFileLayer);
222
223     if (fseek(f, offset, SEEK_SET) != 0)
224       return 0;
225   }
226
227   cdf->dataoffset = offset;
228
229   return 1;
230 }
231
232 static int cdf_write_header(CDataFile *cdf)
233 {
234   CDataFileHeader *header;
235   CDataFileImageHeader *image;
236   CDataFileMeshHeader *mesh;
237   CDataFileLayer *layer;
238   FILE *f = cdf->writef;
239   int a;
240
241   header = &cdf->header;
242
243   if (!fwrite(header, sizeof(CDataFileHeader), 1, f))
244     return 0;
245
246   if (header->type == CDF_TYPE_IMAGE) {
247     image = &cdf->btype.image;
248     if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f))
249       return 0;
250   }
251   else if (header->type == CDF_TYPE_MESH) {
252     mesh = &cdf->btype.mesh;
253     if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f))
254       return 0;
255   }
256
257   for (a = 0; a < header->totlayer; a++) {
258     layer = &cdf->layer[a];
259
260     if (!fwrite(layer, sizeof(CDataFileLayer), 1, f))
261       return 0;
262   }
263
264   return 1;
265 }
266
267 bool cdf_read_open(CDataFile *cdf, const char *filename)
268 {
269   FILE *f;
270
271   f = BLI_fopen(filename, "rb");
272   if (!f)
273     return 0;
274
275   cdf->readf = f;
276
277   if (!cdf_read_header(cdf)) {
278     cdf_read_close(cdf);
279     return 0;
280   }
281
282   if (cdf->header.type != cdf->type) {
283     cdf_read_close(cdf);
284     return 0;
285   }
286
287   return 1;
288 }
289
290 bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
291 {
292   size_t offset;
293   int a;
294
295   /* seek to right location in file */
296   offset = cdf->dataoffset;
297   for (a = 0; a < cdf->totlayer; a++) {
298     if (&cdf->layer[a] == blay)
299       break;
300     else
301       offset += cdf->layer[a].datasize;
302   }
303
304   return (fseek(cdf->readf, offset, SEEK_SET) == 0);
305 }
306
307 bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
308 {
309   /* read data */
310   if (!fread(data, size, 1, cdf->readf))
311     return 0;
312
313   /* switch endian if necessary */
314   if (cdf->switchendian) {
315     BLI_endian_switch_float_array(data, size / sizeof(float));
316   }
317
318   return 1;
319 }
320
321 void cdf_read_close(CDataFile *cdf)
322 {
323   if (cdf->readf) {
324     fclose(cdf->readf);
325     cdf->readf = NULL;
326   }
327 }
328
329 bool cdf_write_open(CDataFile *cdf, const char *filename)
330 {
331   CDataFileHeader *header;
332   CDataFileImageHeader *image;
333   CDataFileMeshHeader *mesh;
334   FILE *f;
335
336   f = BLI_fopen(filename, "wb");
337   if (!f)
338     return 0;
339
340   cdf->writef = f;
341
342   /* fill header */
343   header = &cdf->header;
344   /* strcpy(, "BCDF"); // terminator out of range */
345   header->ID[0] = 'B';
346   header->ID[1] = 'C';
347   header->ID[2] = 'D';
348   header->ID[3] = 'F';
349   header->endian = cdf_endian();
350   header->version = CDF_VERSION;
351   header->subversion = CDF_SUBVERSION;
352
353   header->structbytes = sizeof(CDataFileHeader);
354   header->type = cdf->type;
355   header->totlayer = cdf->totlayer;
356
357   if (cdf->type == CDF_TYPE_IMAGE) {
358     /* fill image header */
359     image = &cdf->btype.image;
360     image->structbytes = sizeof(CDataFileImageHeader);
361     image->tile_size = CDF_TILE_SIZE;
362   }
363   else if (cdf->type == CDF_TYPE_MESH) {
364     /* fill mesh header */
365     mesh = &cdf->btype.mesh;
366     mesh->structbytes = sizeof(CDataFileMeshHeader);
367   }
368
369   cdf_write_header(cdf);
370
371   return 1;
372 }
373
374 bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
375 {
376   return 1;
377 }
378
379 bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
380 {
381   /* write data */
382   if (!fwrite(data, size, 1, cdf->writef))
383     return 0;
384
385   return 1;
386 }
387
388 void cdf_write_close(CDataFile *cdf)
389 {
390   if (cdf->writef) {
391     fclose(cdf->writef);
392     cdf->writef = NULL;
393   }
394 }
395
396 void cdf_remove(const char *filename)
397 {
398   BLI_delete(filename, false, false);
399 }
400
401 /********************************** Layers ***********************************/
402
403 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
404 {
405   CDataFileLayer *layer;
406   int a;
407
408   for (a = 0; a < cdf->totlayer; a++) {
409     layer = &cdf->layer[a];
410
411     if (layer->type == type && STREQ(layer->name, name))
412       return layer;
413   }
414
415   return NULL;
416 }
417
418 CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
419 {
420   CDataFileLayer *newlayer, *layer;
421
422   /* expand array */
423   newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
424   memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
425   cdf->layer = newlayer;
426
427   cdf->totlayer++;
428
429   /* fill in new layer */
430   layer = &cdf->layer[cdf->totlayer - 1];
431   layer->structbytes = sizeof(CDataFileLayer);
432   layer->datatype = CDF_DATA_FLOAT;
433   layer->datasize = datasize;
434   layer->type = type;
435   BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
436
437   return layer;
438 }