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