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