split BKE_utildefines.h, now it only has blender specific defines like GS() MAKE_ID...
[blender.git] / source / blender / blenkernel / intern / customdata_file.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_fileops.h"
30 #include "BLI_string.h"
31 #include "BLI_utildefines.h"
32
33 #include "BKE_customdata_file.h"
34 #include "BKE_global.h"
35 #include "BKE_utildefines.h"
36
37 /************************* File Format Definitions ***************************/
38
39 #define CDF_ENDIAN_LITTLE       0
40 #define CDF_ENDIAN_BIG          1
41
42 #define CDF_DATA_FLOAT  0
43
44 typedef struct CDataFileHeader {
45         char ID[4];                                     /* "BCDF" */
46         char endian;                            /* little, big */
47         char version;                           /* non-compatible versions */
48         char subversion;                        /* compatible sub versions */
49         char pad;                                       /* padding */
50
51         int structbytes;                        /* size of this struct in bytes */
52         int type;                                       /* image, mesh */
53         int totlayer;                           /* number of layers in the file */
54 } CDataFileHeader;
55
56 typedef struct CDataFileImageHeader {
57         int structbytes;                        /* size of this struct in bytes */
58         int width;                                      /* image width */
59         int height;                                     /* image height */
60         int tile_size;                          /* tile size (required power of 2) */
61 } CDataFileImageHeader;
62
63 typedef struct CDataFileMeshHeader {
64         int structbytes;                        /* size of this struct in bytes */
65 } CDataFileMeshHeader;
66
67 struct CDataFileLayer {
68         int structbytes;                                /* size of this struct in bytes */
69         int datatype;                                   /* only float for now */
70         uint64_t datasize;                              /* size of data in layer */
71         int type;                                               /* layer type */
72         char name[CDF_LAYER_NAME_MAX];  /* layer name */
73 };
74
75 /**************************** Other Definitions ******************************/
76
77 #define CDF_VERSION                     0
78 #define CDF_SUBVERSION          0
79 #define CDF_TILE_SIZE           64
80
81 struct CDataFile {
82         int type;
83
84         CDataFileHeader header;
85         union {
86                 CDataFileImageHeader image;
87                 CDataFileMeshHeader mesh;
88         } btype;
89
90         CDataFileLayer *layer;
91         int totlayer;
92
93         FILE *readf;
94         FILE *writef;
95         int switchendian;
96         size_t dataoffset;
97 };
98
99 /********************************* Create/Free *******************************/
100
101 static int cdf_endian(void)
102 {
103         if(ENDIAN_ORDER == L_ENDIAN)
104                 return CDF_ENDIAN_LITTLE;
105         else
106                 return CDF_ENDIAN_BIG;
107 }
108
109 /*static int cdf_data_type_size(int datatype)
110 {
111         if(datatype == CDF_DATA_FLOAT)
112                 return sizeof(float);
113         
114         return 0;
115 }*/
116
117 CDataFile *cdf_create(int type)
118 {
119         CDataFile *cdf= MEM_callocN(sizeof(CDataFile), "CDataFile");
120
121         cdf->type= type;
122
123         return cdf;
124 }
125
126 void cdf_free(CDataFile *cdf)
127 {
128         cdf_read_close(cdf);
129         cdf_write_close(cdf);
130
131         if(cdf->layer)
132                 MEM_freeN(cdf->layer);
133
134         MEM_freeN(cdf);
135 }
136
137 /********************************* Read/Write ********************************/
138
139 static int cdf_read_header(CDataFile *cdf)
140 {
141         CDataFileHeader *header;
142         CDataFileImageHeader *image;
143         CDataFileMeshHeader *mesh;
144         CDataFileLayer *layer;
145         FILE *f= cdf->readf;
146         size_t offset = 0;
147         int a;
148
149         header= &cdf->header;
150
151         if(!fread(header, sizeof(CDataFileHeader), 1, cdf->readf))
152                 return 0;
153         
154         if(memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0)
155                 return 0;
156         if(header->version > CDF_VERSION)
157                 return 0;
158
159         cdf->switchendian= header->endian != cdf_endian();
160         header->endian= cdf_endian();
161
162         if(cdf->switchendian) {
163                 SWITCH_INT(header->type);
164                 SWITCH_INT(header->totlayer);
165                 SWITCH_INT(header->structbytes);
166         }
167
168         if(!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH))
169                 return 0;
170
171         offset += header->structbytes;
172         header->structbytes= sizeof(CDataFileHeader);
173
174         if(fseek(f, offset, SEEK_SET) != 0)
175                 return 0;
176         
177         if(header->type == CDF_TYPE_IMAGE) {
178                 image= &cdf->btype.image;
179                 if(!fread(image, sizeof(CDataFileImageHeader), 1, f))
180                         return 0;
181
182                 if(cdf->switchendian) {
183                         SWITCH_INT(image->width);
184                         SWITCH_INT(image->height);
185                         SWITCH_INT(image->tile_size);
186                         SWITCH_INT(image->structbytes);
187                 }
188
189                 offset += image->structbytes;
190                 image->structbytes= sizeof(CDataFileImageHeader);
191         }
192         else if(header->type == CDF_TYPE_MESH) {
193                 mesh= &cdf->btype.mesh;
194                 if(!fread(mesh, sizeof(CDataFileMeshHeader), 1, f))
195                         return 0;
196
197                 if(cdf->switchendian)
198                         SWITCH_INT(mesh->structbytes);
199
200                 offset += mesh->structbytes;
201                 mesh->structbytes= sizeof(CDataFileMeshHeader);
202         }
203
204         if(fseek(f, offset, SEEK_SET) != 0)
205                 return 0;
206
207         cdf->layer= MEM_callocN(sizeof(CDataFileLayer)*header->totlayer, "CDataFileLayer");
208         cdf->totlayer= header->totlayer;
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                         SWITCH_INT(layer->type);
218                         SWITCH_INT(layer->datatype);
219                         SWITCH_INT64(layer->datasize);
220                         SWITCH_INT(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 int cdf_read_open(CDataFile *cdf, char *filename)
274 {
275         FILE *f;
276
277         f= 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 int 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 int cdf_read_data(CDataFile *cdf, int size, void *data)
314 {
315         float *fdata;
316         int a;
317         
318         /* read data */
319         if(!fread(data, size, 1, cdf->readf))
320                 return 0;
321
322         /* switch endian if necessary */
323         if(cdf->switchendian) {
324                 fdata= data;
325
326                 for(a=0; a<size/sizeof(float); a++)
327                         SWITCH_INT(fdata[a])
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, char *filename)
342 {
343         CDataFileHeader *header;
344         CDataFileImageHeader *image;
345         CDataFileMeshHeader *mesh;
346         FILE *f;
347
348         f= 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, 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(char *filename)
406 {
407         BLI_delete(filename, 0, 0);
408 }
409
410 /********************************** Layers ***********************************/
411
412 CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, 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, 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