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