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